[Development] Fix a Virto Commerce module's embedded Vue 3 \"shell\" sub-app (@vc-shell/framework, e.g. vc-module-pagebuilder's src/VirtoCommerce.PageBuilderModule.Web/Apps/page-builder-shell/) declared in skills/qa-fix-routing/fix-repos.json moduleFrontendSubApps. State/logic bugs (composable/store/service function) are proven red→green with the sub-app's OWN real `tsx --test` runner + plain Vue reactivity (ref/computed/watch/effectScope) — no stubbing needed, unlike angular-admin's scratch ...
Scanned 9/20/2026
Install to Claude Code
npx -y skills add VirtoCommerce/vc-mcp-testing-module --skill vc-shell-fix --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Vc Shell Fix?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/virtocommerce-vc-shell-fix-vc-mcp-testing-module)More formats (shields.io, HTML) on the badges page.
---
name: vc-shell-fix
description: "[Development] Fix a Virto Commerce module's embedded Vue 3 \"shell\" sub-app (@vc-shell/framework, e.g. vc-module-pagebuilder's src/VirtoCommerce.PageBuilderModule.Web/Apps/page-builder-shell/) declared in skills/qa-fix-routing/fix-repos.json moduleFrontendSubApps. State/logic bugs (composable/store/service function) are proven red→green with the sub-app's OWN real `tsx --test` runner + plain Vue reactivity (ref/computed/watch/effectScope) — no stubbing needed, unlike angular-admin's scratch harness, because `vue` is a real importable package. Mounted-component/template/DOM bugs (rendering, event binding, slot/prop output, CSS/layout) need an EPHEMERAL, never-committed vitest+@vue/test-utils+jsdom harness reusing the sub-app's own vite.config.ts — stripped from the diff before the PR. Used by the fullstack-frontend developer agent in /qa-fix when the RCA anchor falls under a declared module sub-app path (still single-repo)."
---
# /vc-shell-fix — Fix a module-embedded Vue 3 shell sub-app
Fix a bug in a `vc-module-*` repo's embedded Vue 3 "shell" sub-app (`@vc-shell/framework`), declared in
`skills/qa-fix-routing/fix-repos.json` `moduleFrontendSubApps` and matched by `skills/qa-fix-routing/repo-router.ts`
`resolveOwningSubApp()`. Because the sub-app ships **inside the module repo**, this is still a
**single-repo** fix (Gate 1 passes) — but it's owned by `fullstack-frontend`, not `fullstack-backend`,
since the sub-app is a genuinely different stack from the module's own C#/AngularJS Admin UI.
## Reality check (read this first)
The sub-app is a **real** Vue 3 + Vite + vee-validate app with its own `package.json`/`vite.config.ts`/
`tsconfig.json` — NOT hand-rolled like the legacy AngularJS Admin SPA (`/angular-admin`). As of today's
only declared sub-app (page-builder), its shipped test tooling is Node's built-in `tsx --test` over
`tests/**/*.test.ts` — no `@vue/test-utils`, no jsdom, no Storybook. **Don't treat that as a permanent
fact** — `moduleFrontendSubApps` can grow, and a future sub-app might ship `vitest`/`@vue/test-utils`
natively. Confirm from the actual sub-app's `package.json` (`scripts` + `devDependencies` — see "Ground
yourself in the checked-out repo first" below) before assuming Path 2's ephemeral harness is needed.
Because Vue 3's reactivity primitives (`ref`/`computed`/`watch`/`effectScope`) run **standalone in plain
Node** — no DOM needed — a bug whose root cause is **state/reactivity logic** (a composable, a store, a
service function) is provable with the sub-app's REAL `tsx --test` runner, **zero new tooling**. This is
the common case, not the exception — contrast with `/angular-admin`, where even a pure logic bug needs a
stub, because `angular` (the AngularJS global) isn't a real importable package the way `vue` is.
Only a **mounted-component / template / DOM** bug (rendering, event binding, slot/prop output,
CSS/layout) genuinely needs SFC compilation + jsdom, which the sub-app doesn't ship — that's the one case
needing new (ephemeral, never-committed) tooling.
## When to use
`/qa-fix` Gate 1 routed a `module`-kind repo, AND `resolveOwningSubApp()` matched the RCA anchor to a
sub-app declared in `moduleFrontendSubApps` (e.g. `vc-module-pagebuilder`'s `src/VirtoCommerce.PageBuilderModule.Web/Apps/page-builder-shell/`).
Working directory for install/build/test/typecheck/lint = `<checkout>/<subApp.path>`; repo-level git ops
(`git diff`/`add`/`commit`/`push`) still happen at the **repo root** — one commit, one repo.
## Ground yourself in the checked-out repo first
The sub-app's own files are the source of truth — do NOT assume versions, a package manager, or script
names from this skill (they drift; the page-builder shell's own `.claude` docs already disagree with its
`package.json` on the `@vc-shell/framework` version).
1. **Read the sub-app's `package.json`.** The `scripts` block tells you exactly how to run
`test` / `type-check` / `lint` / `build`; the `packageManager` field tells you *with what* (e.g.
`yarn@4.9.2` → invoke `yarn test`, not `npm`/bare `npx`). Its dependency versions (Vue, Vite, the
framework) are authoritative — never hardcode them.
2. **If the module repo ships its own `.claude/agents/*` or `.claude/skills/*`, read them.** Some module
repos (e.g. `vc-module-pagebuilder`) carry first-party dev docs — structure, build commands, the
`api_client/` rule, framework conventions. Treat them as the module team's own guidance and prefer
them over generic assumptions — but where they disagree with `package.json`, **`package.json` wins**.
3. **Know the layout** (typical `@vc-shell` shell): `src/composables/` (`useXxx`), `src/modules/`
(feature modules), `src/pages/` (route = file), `src/router/`, `src/locales/` (i18n), and
`src/api_client/` — **auto-generated, off-limits** (see Hard rules).
## Two fix paths
1. **State/logic bug** (composable, store, service function — e.g. a stale reactive flag not resetting
after an action) → **Path 1**, below. Try this first.
2. **Mounted-component/template/DOM bug** (rendering, event binding, slot/prop output, CSS/layout) →
**Path 2**, below — the ephemeral harness.
3. A bug needing live wiring (real router/store/backend API responses) that **neither** path can
faithfully reproduce → this is **not** a tooling gap to solve here. It's the ordinary Gate-6 "needs
deploy verification" path every module fix already uses (`.claude/rules/quality-gates.md` G6,
`qa-backend-expert` post-deploy regression) — say so in the PR body, don't invent a new harness.
**This includes cross-frame bugs:** the Angular designer ↔ Vue shell communicate across an **iframe**
via `postMessage` + `BroadcastChannel('vc-module-content-channel')`, which neither Path 1 (Node) nor
Path 2 (single-frame jsdom) can reproduce — a "state doesn't update across the designer" symptom is a
Gate-6 case, not a harness case.
### Path 1 — state/logic, the real runner (preferred — try this first)
1. Read `tests/**/*.test.ts` for the house style (Node's built-in `test`/`assert` from `node:test`,
plain imports — no test framework config to discover).
2. Locate the seam: the composable (`use*`)/store/service function that owns the bug's state — usually
under `src/composables/` or `src/modules/` (see the layout above). `Grep`/`Glob` on the symptom
(a flag name, an event handler, a store action). Never the seam: `src/api_client/` (generated).
3. Write a **NEW** `*.test.ts` next to an existing one: import the real module, wrap reactive state in
`effectScope()` where needed (same technique as `vue-unit-test`'s `vitest-patterns.md` composable
recipe — different runner, same idea), assert the **expected** behavior.
4. Confirm **RED** by running just the new file with the sub-app's runner (e.g.
`yarn tsx --test tests/<new>.test.ts` — the runner + PM from "Ground yourself" step 1 above). If it
passes on current code, the RCA is wrong — re-investigate, don't proceed.
5. Fix the smallest correct change to product code; re-run until **GREEN**. Existing tests untouched.
6. Gate: run the sub-app's **declared** `type-check`, `lint`, and `test` scripts via its `packageManager`
(e.g. `yarn type-check && yarn lint && yarn test` when `packageManager` is yarn — see "Ground yourself"
step 1 above). Note `lint` is often `eslint --fix` (it mutates files): review that its auto-fixes stay
within your fix scope before committing.
### Path 2 — mounted-component/DOM, the ephemeral harness
1. **Confirm Path 1 genuinely can't reach the bug** — the symptom is in template/render output, not
state (if you're not sure, try Path 1 first; it's cheaper and leaves no cleanup).
2. **Scratch-install the mount deps (`vitest @vue/test-utils jsdom @vitejs/plugin-vue`) without touching
any tracked file** — no diff to `package.json`, `yarn.lock`, or `package-lock.json`. The deps only
need to land in the gitignored `node_modules`. Verify with a clean `git status` **before and after**,
whatever the package manager. The exact recipe (incl. the Yarn Berry caveat) is in
`vc-shell-scratch-harness-patterns.md` §1.
3. Write an ephemeral `vitest.scratch.config.ts` in the sub-app dir (never staged) that imports the
sub-app's **real** `vite.config.ts` via `mergeConfig`, setting `test.environment: "jsdom"` — see
`vc-shell-scratch-harness-patterns.md` for the exact snippet.
4. Write the repro as a normal `@vue/test-utils` mount test in a scratch location
(`.fix-workspace/_scratch/VCST-XXXX/repro.spec.ts` — outside the sub-app tree), importing the REAL
component from the checkout.
5. Run: `npx vitest run --config <path-to-scratch-config> .fix-workspace/_scratch/VCST-XXXX/repro.spec.ts`.
Confirm **RED** on current code → fix product code → confirm **GREEN**.
6. **Before the PR:** `git status`/`git diff` in the sub-app directory must show **nothing** from steps
2–4 — no `package.json`, no lockfile, no scratch config, no `node_modules` (gitignored anyway). Only
the product-code fix ships. Paste both runs' output in the PR body as evidence (mirrors
`/angular-admin`'s scratch-harness discipline exactly).
## Hard rules
- **Single repo, single sub-app path.** Touching `Web/Scripts/` (legacy AngularJS Admin UI), the Angular
21 designer, or the .NET solution in the same run → STOP. Stay within the declared sub-app path.
- **`src/api_client/` is auto-generated** (`@vc-shell/api-client-generator`) — **never edit it.** An RCA
anchor inside `api_client/` means the real root cause is upstream (a C# DTO/controller or the generator
config), not the shell → **STOP / hand off**; this is not a shell fix.
- **The ephemeral harness (Path 2) never ships.** No devDependency, lockfile, or scratch-config diff —
verify with `git status`/`git diff` before opening the PR.
- **Only ADD tests** (Path 1) — never edit or delete an existing `tests/*.test.ts`. An existing test
going red after the fix = contract conflict → STOP.
- **Never add a real dependency** to the sub-app's `package.json` just to compile a test.
- **Idiomatic minimal diff — match the sub-app's conventions**, don't restyle or "modernize":
`<script setup lang="ts">`, `readonly` refs where nothing mutates them, vee-validate for **all** form
validation (no custom validators), and i18n via `useI18n()` + `locales/` keys (**no hardcoded strings**).
- Same gate ladder + no-auto-merge as every other developer path — `.claude/rules/quality-gates.md`.
- If the correct fix is unclear or risky → `FIX_STATUS: FAILED`, don't push speculative changes.
## References
- `vc-shell-scratch-harness-patterns.md` — Path-2 mechanics in full (scratch install, `mergeConfig`
snippet, worked red→green mount-test example, pre-PR strip checklist)
- `skills/vue-unit-test/vitest-patterns.md` — mount/composable recipes (shared technique with vc-frontend)
- `skills/vue-fix/vue3-best-practices.md` — Vue 3/TS idioms within a minimal diff
- `knowledge/architecture/vc-module-architecture.md` §2a — embedded frontend sub-apps in a module repo
- `.claude/rules/quality-gates.md` — G1 (routing), G2 (red), G3 (green), G4 (scratch-harness leakage check)
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!