---
name: nuxt-data-audit
description: "Audit a Nuxt consumer's data-fetching and performance patterns against the golden path checklist (14 items). Scans .vue/.ts files for useFetch/useAsyncData/$fetch/useQuery/useMutation usage, checks dedupe/cache/key/payload/lazy/routeRules compliance. Outputs a graded report with per-item scores and top-3 actionable improvements."
effort: medium
metadata:
  author: clade
  version: "1.0"
---
<!-- 🔒 LOCKED — managed by clade · auto-generated by sync-to-agents; edit source in .claude/ then re-run sync -->

`/nuxt-data-audit` — Nuxt data-fetching & performance golden path audit.

Reference rule：`rules/core/nuxt-data-perf.md`
Cookbook：`~/offline/clade/vendor/snippets/nuxt-data-perf/`

## 何時跑

- **定期稽核**：跨 consumer fleet 完善度掃描（從 clade home 跑，指定 consumer path）
- **新功能完成後**：對 consumer 當前 codebase 的 data-fetching 品質做 baseline check
- **code-review 輔助**：reviewer 可跑此 skill 取得量化數據輔助 review
- **新 consumer onboard**：day-1 baseline 建立

## 怎麼跑

```
/nuxt-data-audit                          # 掃當前 cwd 的 consumer
/nuxt-data-audit ~/offline/TDMS           # 掃指定 consumer
/nuxt-data-audit --fleet                  # 掃全 fleet（從 clade home 用 registry/consumers.json）
```

## Phase 1 — Dependency Detection

判斷 consumer 的 data-fetching stack：

```bash
# 檢查 package.json
grep -E '@pinia/colada|@pinia/colada-nuxt|@pinia/nuxt' package.json
```

分為兩類：
- **Colada consumer**：安裝了 @pinia/colada → 全 14 項 checklist 適用
- **Non-Colada consumer**：未安裝 → E9/E10 標 N/A，其他 12 項適用

## Phase 2 — Automated Scan

對每項 checklist 跑 grep/AST 掃描。以下是每項的掃描方法：

### E1 — setup 無裸 $fetch（HR-1）

```bash
# 找 .vue 檔中 <script setup> 的 $fetch（排除 event handler）
# 注意 $csrfFetch 等 alias 也要查
find . -name '*.vue' -not -path '*/node_modules/*' -not -path '*/.nuxt/*' -not -path '*/test/*' \
  | xargs grep -l '\$fetch\|\$csrfFetch'
```

**對每個命中檔案**：讀取 `<script setup>` 區塊，判斷 $fetch 是否在 top-level（fail）還是在 function/handler 內（pass）。Top-level = 不在任何 function/arrow/method 定義內的 await $fetch。

**判定**：
- pass：所有 $fetch 都在 event handler / function 內
- partial：部分在 top-level 但有 useAsyncData 包裹
- fail：有裸 top-level $fetch

### E2 — useFetch 有適當 key（HR-4 useFetch 部分）

```bash
grep -rn 'useFetch\|useAsyncData' --include='*.ts' --include='*.vue' \
  | grep -v node_modules | grep -v .nuxt | grep -v test/
```

**判定**：custom composable（`composables/*.ts` / `queries/*.ts`）內的 useFetch 是否手動指定 key。Page/component 內的 useFetch 自動生成 key 通常 OK。

### E3 — 高頻 endpoint 有 dedupe:'defer'（HR-2）

```bash
# 找所有 useFetch 呼叫
grep -rn 'useFetch\|\.refresh(' --include='*.vue' --include='*.ts' \
  | grep -v node_modules | grep -v .nuxt
# 檢查有沒有 dedupe
grep -rn "dedupe" --include='*.vue' --include='*.ts' \
  | grep -v node_modules | grep -v .nuxt
```

**判定**：有 @click / @submit handler 觸發 fetch 且無 dedupe → fail。

### E4 — Reference data 有 cache 策略（HR-3）

```bash
# Colada consumer：檢查 staleTime 使用率
grep -rn 'staleTime' --include='*.ts' --include='*.vue' | grep -v node_modules | grep -v .nuxt
# Non-Colada：檢查 getCachedData
grep -rn 'getCachedData' --include='*.ts' --include='*.vue' | grep -v node_modules | grep -v .nuxt
```

**判定**：staleTime/getCachedData count vs useQuery/useFetch count。比率 > 50% = pass，> 20% = partial，< 20% = fail。

### E5 — 大 payload 有 pick/transform（SR-1）

```bash
grep -rn 'pick:\|transform:' --include='*.ts' --include='*.vue' \
  | grep -v node_modules | grep -v .nuxt | grep -v test/ | grep -v nuxt.config | grep -v vite.config
```

**判定**：有 useFetch/useQuery 但 0 pick/transform → fail。有至少一些 → partial。

### E6 — 非首屏 component 有 Lazy prefix（SR-2）

```bash
grep -rn '<Lazy' --include='*.vue' | grep -v node_modules | grep -v .nuxt
```

**判定**：0 = fail。> 0 但 < component 總數 10% = partial。> 10% = pass。

### E7 — routeRules 有 performance 設定（SR-3）

```bash
grep -A20 'routeRules' nuxt.config.ts | grep -E 'prerender|swr|isr|ssr:\s*false'
```

**判定**：有 prerender/swr/isr = pass。只有 csurf/security = partial。完全沒有 = fail。

### E8 — NuxtImg 最佳化（SR-5）

```bash
grep -rn '<NuxtImg\|<nuxt-img' --include='*.vue' | grep -v node_modules | grep -v .nuxt
# 檢查有沒有 format/loading/priority
grep -rn 'format=.*webp\|loading=.*lazy\|fetchpriority\|:preload=' --include='*.vue' | grep -v node_modules
```

**判定**：@nuxt/image 已安裝 + NuxtImg 有 format/loading → pass。裝了但沒 optimize → partial。沒裝 → N/A（不強制）。

### E9 — Colada key factory（HR-4，Colada only）

```bash
# Key factory pattern
grep -rn 'Keys\s*=\|KEYS\.\|queryKeys\|defineQueryOptions' --include='*.ts' | grep -v node_modules | grep -v .nuxt
# Magic string keys
grep -rn "key:\s*\['" --include='*.ts' --include='*.vue' | grep -v node_modules | grep -v .nuxt | grep -v test/
```

**判定**：factory count > magic string count = pass。反之 = fail。

### E10 — useMutation 有 cache invalidation（HR-5，Colada only）

```bash
mutation_files=$(grep -rl 'useMutation' --include='*.ts' --include='*.vue' | grep -v node_modules | grep -v .nuxt | grep -v test/)
invalidate_files=$(grep -rl 'invalidateQueries' --include='*.ts' --include='*.vue' | grep -v node_modules | grep -v .nuxt | grep -v test/)
```

**判定**：invalidation files >= mutation files = pass。差距 > 30% = fail。

### E11 — 無跨 request state 污染

```bash
grep -rn 'export const.*= ref(\|export const.*= reactive(' --include='*.ts' \
  | grep -v node_modules | grep -v .nuxt | grep -v test/ | grep -v defineStore
```

**判定**：0 hits = pass。> 0 = fail（嚴重 — SSR cross-request 污染）。

### E12 — Error handling 完整

對 useFetch/useQuery 呼叫：檢查 `error` ref 是否被 template 消費（`v-if="error"`、`{{ error }}`）或 watch。

**判定**：> 50% 有 error 消費 = pass。< 50% = partial。0 = fail。

### E13 — 平行 request 用 Promise.all

```bash
grep -rn 'Promise.all' --include='*.ts' --include='*.vue' | grep -v node_modules | grep -v .nuxt
```

**判定**：advisory，有就加分。

### E14 — watch/immediate 合理

```bash
grep -rn 'immediate:\s*false\|watch:\s*\[' --include='*.ts' --include='*.vue' \
  | grep -v node_modules | grep -v .nuxt | grep -v test/
```

**判定**：有使用 = pass。全部預設 = partial。

## Phase 3 — Grading

| Grade | 條件 |
|-------|------|
| A | 全部 HR pass + ≥ 80% SR pass |
| B | 全部 HR pass（SR 可 partial） |
| C | ≥ 3 HR pass，其他 partial |
| D | < 3 HR pass |
| F | E1 或 E11 fail（SSR 安全問題） |

HR（Hard Rules）= E1, E3, E4 (cache), E9 (key factory), E10 (invalidation), E11 (state safety)
SR（Should Rules）= E2, E5, E6, E7, E8, E12, E13, E14

## Phase 4 — Report Output

### Single consumer

```
## nuxt-data-audit report: <consumer>

Grade: B+
Stack: Pinia Colada 1.3.1 + useFetch (mixed)

| # | Check | Score | Detail |
|---|-------|-------|--------|
| E1 | setup 無裸 $fetch | ✅ pass | 0 violations |
| E2 | useFetch key | ✅ pass | 3/3 custom composables have explicit key |
| E3 | dedupe | ❌ fail | 0/15 high-freq endpoints have dedupe |
| ... | ... | ... | ... |

### Top 3 Improvements
1. **E3 dedupe** — 15 endpoints in 8 files need dedupe:'defer' [files listed]
2. **E9 key factory** — 7 magic string keys should migrate to factory [files listed]
3. **E5 pick/transform** — 5 list endpoints return full rows [files listed]
```

### Fleet mode（--fleet）

```
## nuxt-data-audit fleet report

| Consumer | Grade | E1 | E2 | E3 | E4 | E5 | E6 | ... |
|----------|-------|----|----|----|----|----|----|-----|
| perno | A- | ✅ | ✅ | ❌ | ✅✅ | ⚠️ | ❌ | ... |
| TDMS | B+ | ⚠️ | ✅ | ❌ | ✅ | ✅ | ✅✅ | ... |
| ... | ... | ... | ... | ... | ... | ... | ... | ... |

### Fleet-wide gaps (priority order)
1. E3 dedupe — 0/7 consumers pass
2. E7 routeRules — 1/7 consumers pass
3. E6 Lazy — 2/7 consumers pass
```

## Enforcement Integration

本 skill 的 rule（`rules/core/nuxt-data-perf.md`）透過 `paths` frontmatter 在觸及 `.vue/.ts` 時自動載入。但 rule 被載入 ≠ rule 被遵守。以下是三層 enforcement：

### Layer 1 — Rule Self-check Gate（寫 code 時）

Rule 內含：**每次寫完新的 useFetch / useQuery / $fetch 呼叫後，MUST 對照 HR-1~HR-5 自查**。4.8 會字面遵守此指令。

### Layer 2 — Code Review Cross-check（review 時）

`/code-review` 對 diff 中新增的 data-fetching 呼叫，SHOULD 跑以下 quick check：
- 新的 useFetch 有 dedupe 嗎？
- 新的 useQuery 有 staleTime 嗎？
- 新的 useMutation 有 invalidateQueries 嗎？
- 新的 $fetch 在 setup top-level 嗎？

### Layer 3 — Periodic Fleet Audit（定期）

從 clade home 跑 `/nuxt-data-audit --fleet`，更新 HANDOFF.md 稽核 baseline。
