Yuki Takei 1 месяц назад
Родитель
Сommit
a2cce95bd8

+ 0 - 229
.kiro/specs/reduce-modules-loaded/analysis-ledger.md

@@ -1,229 +0,0 @@
-# Analysis Ledger
-
-## Measurements
-
-### Legacy KPI (total modules from `Compiled ... (N modules)`)
-| Step | Task | Modules | Time | Date |
-|------|------|---------|------|------|
-| Baseline (no changes) | 1.1 | 10,066 | ~31s | 2026-02-19 |
-| + optimizePackageImports only | 2.2 | 10,279 (+213) | ~31.1s | 2026-02-19 |
-| + all Phase 1 changes | 7.1 | 10,281 (+215) | ~31.6s | 2026-02-19 |
-| Committed changes (no optimizePkgImports) | 7.1 | 10,068 (+2) | ~30.8s | 2026-02-19 |
-| Revert only optimizePkgImports | bisect | 10,068 | ~30.8s | 2026-02-19 |
-| Revert only locale-utils fix | bisect | 10,279 | ~31.2s | 2026-02-19 |
-| Revert only serializer fix | bisect | 10,281 | ~31.2s | 2026-02-19 |
-| Revert only axios fix | bisect | 10,281 | ~31.1s | 2026-02-19 |
-
-> **Note**: Total module count includes both initial (eager) and async (lazy) chunks. Dynamic imports move modules to async chunks without reducing the total, so this metric does NOT reflect lazy-loading improvements. Replaced by ChunkModuleStats KPI below.
-
-### New KPI: ChunkModuleStats (initial / async-only / total)
-
-Measured via `ChunkModuleStatsPlugin` in `next.config.utils.js`. The `initial` count represents modules loaded eagerly on page access — this is the primary reduction target.
-
-| Step | Task | initial | async-only | total | Compiled modules | Date |
-|------|------|---------|------------|-------|------------------|------|
-| **Baseline (no Phase 2 changes)** | 8.1 | **2,704** | 4,146 | 6,850 | 10,068 | 2026-02-20 |
-| + MermaidViewer dynamic + date-fns subpath | 8.3 | **2,128** | 4,717 | 6,845 | 10,058 | 2026-02-20 |
-| + date-fns locale subpath imports | 8.4 | **1,630** | 4,717 | 6,347 | 9,062 | 2026-02-20 |
-| + null-loader: i18next-fs-backend, bunyan, bunyan-format | 8.5 | **1,572** | 4,720 | 6,292 | 9,007 | 2026-02-20 |
-| + validator → isMongoId regex in LinkEditModal | 8.6 | **1,572** | 4,608 (-112) | 6,180 (-112) | 8,895 (-112) | 2026-02-20 |
-| + react-hotkeys → tinykeys migration | 8.7 | **1,573** (+1) | 4,516 (-92) | 6,089 (-91) | 8,802 (-93) | 2026-02-24 |
-| + markdown pipeline → next/dynamic({ ssr: true }) | 8.8 | **1,073** (-500) | 5,016 (+500) | 6,089 (0) | 8,803 (+1) | 2026-02-24 |
-| + core-js null-load + analysis plugin fix | 8.9 | **894** (-179) | 5,011 (-5) | 5,905 (-184) | 8,619 (-184) | 2026-02-24 |
-| + react-syntax-highlighter deep ESM import + v16 upgrade | 8.10 | **895** (+1) | 4,775 (-236) | 5,670 (-235) | — | 2026-02-26 |
-
-> **Note**: Originally reported baseline was 51.5s, but automated measurement on the same machine consistently shows ~31s. The 51.5s figure may reflect cold cache, different system load, or an earlier codebase state.
-
-### Measurement Method
-
-**Automated (Phase 2+)**:
-
-```bash
-# One-command measurement — cleans .next, starts next dev, triggers compilation, outputs results
-./apps/app/bin/measure-chunk-stats.sh        # default port 3099
-./apps/app/bin/measure-chunk-stats.sh 3001   # custom port
-```
-
-Output: `[ChunkModuleStats] initial: N, async-only: N, total: N` + `Compiled /[[...path]] in Xs (N modules)`
-
-**Manual (Phase 1, legacy)**:
-
-```bash
-rm -rf apps/app/.next
-cd apps/app && node_modules/.bin/next dev -p 3000 &
-curl -s http://localhost:3000/
-# Read log output, then: pkill -f "next dev"
-```
-
-**Key details**:
-- `next dev` can be started without MongoDB — it compiles pages on-demand via webpack regardless of database connectivity
-- Compilation is triggered by HTTP access (curl), not by server startup alone (Next.js uses on-demand compilation)
-- `ChunkModuleStatsPlugin` (in `src/utils/next.config.utils.js`) separates modules into initial (eager) vs async-only (lazy) chunks
-- The `initial` count is the primary KPI — modules the browser must load on first page access
-
-## Import Violations (Task 3)
-| # | File | Violation | Fix Strategy | Status |
-|---|------|-----------|--------------|--------|
-| 1 | src/client/components/RecentActivity/ActivityListItem.tsx | imports `getLocale` from `~/server/util/locale-utils` | Extracted `getLocale` to `src/utils/locale-utils.ts`; client imports from shared module | done |
-| 2 | src/client/components/InAppNotification/ModelNotification/PageBulkExportJobModelNotification.tsx | imports `~/models/serializers/in-app-notification-snapshot/page-bulk-export-job` which has `import mongoose from 'mongoose'` | Created `page-bulk-export-job-client.ts` with `parseSnapshot` + `IPageBulkExportJobSnapshot`; client imports from client module | done |
-
-## Server Packages in Client Bundle (Task 4)
-| # | Package | Confirmed in Client Bundle | null-loader Added | Status |
-|---|---------|---------------------------|-------------------|--------|
-| 1 | mongoose | Yes (existing rule) | Yes | done |
-| 2 | dtrace-provider | Yes (existing rule) | Yes | done |
-| 3 | mathjax-full | Yes (existing rule) | Yes | done |
-| 4 | @elastic/elasticsearch* | No (server-only imports) | N/A | done |
-| 5 | passport* | No (server-only imports) | N/A | done |
-| 6 | @aws-sdk/* | No (server-only imports) | N/A | done |
-| 7 | @azure/* | No (server-only imports) | N/A | done |
-| 8 | @google-cloud/storage | No (server-only imports) | N/A | done |
-| 9 | openai | No (only `import type` in interfaces — erased at compile) | N/A | done |
-| 10 | ldapjs | No (server-only imports) | N/A | done |
-| 11 | nodemailer | No (server-only imports) | N/A | done |
-| 12 | multer | No (server-only imports) | N/A | done |
-| 13 | socket.io | No (server uses socket.io; client uses socket.io-client) | N/A | done |
-| 14 | redis / connect-redis | No (server-only imports) | N/A | done |
-| 15 | @opentelemetry/* | No (server-only imports) | N/A | done |
-
-> **Conclusion**: All server-only packages are properly isolated. No additional null-loader rules needed beyond existing mongoose, dtrace-provider, mathjax-full.
-
-## Barrel Exports to Refactor (Task 5)
-| # | File | Issue | Still Impactful After optimizePackageImports? | Status |
-|---|------|-------|-----------------------------------------------|--------|
-| 1 | src/utils/axios/index.ts | `export * from 'axios'` — unused by all consumers (all use default import only) | N/A (always fix) | done |
-| 2 | src/states/ui/editor/index.ts | 7 wildcard `export *` re-exports | No — internal modules, small files, no heavy deps | done (no change needed) |
-| 3 | src/features/page-tree/index.ts | 3-level cascading barrel → hooks, interfaces, states | No — well-scoped domain barrel, types + hooks only | done (no change needed) |
-| 4 | src/features/page-tree/hooks/_inner/index.ts | 8 wildcard `export *` re-exports | No — all small hook files within same feature | done (no change needed) |
-| 5 | src/states/page/index.ts | 2 wildcard `export *` + named exports | No — focused Jotai hooks, no heavy deps | done (no change needed) |
-| 6 | src/states/server-configurations/index.ts | 2 wildcard `export *` | No — small config atoms only | done (no change needed) |
-
-## Phase 1 Sufficiency Assessment (Task 8.1)
-
-### Phase 1 Changes Summary
-
-| # | Change | Category | Description |
-|---|--------|----------|-------------|
-| 1 | `optimizePackageImports` +3 packages | Config | Added reactstrap, react-hook-form, react-markdown |
-| 2 | locale-utils extraction | Import fix | Extracted `getLocale` from `~/server/util/` to `~/utils/` (client-safe) |
-| 3 | Serializer split | Import fix | Created `page-bulk-export-job-client.ts` separating `parseSnapshot` from mongoose-dependent `stringifySnapshot` |
-| 4 | Axios barrel fix | Barrel refactor | Removed `export * from 'axios'` (unused by all 7 consumers) |
-| 5 | null-loader analysis | Investigation | Confirmed all server packages already properly isolated — no additional rules needed |
-| 6 | Internal barrel evaluation | Investigation | Internal barrels (states, features) are small and well-scoped — no changes needed |
-| 7 | LazyLoaded verification | Verification | All 30 LazyLoaded components follow correct dynamic import pattern |
-
-### Actual Measurement Results (A/B Bisection)
-
-| Change Group | Modules | Time | vs Baseline |
-|-------------|---------|------|-------------|
-| Baseline (no changes) | 10,066 | ~31s | — |
-| **optimizePackageImports +3 pkgs** | **10,279** | **~31.1s** | **+213 modules, no time change** |
-| locale-utils fix only | ~10,068 | ~31s | +2 modules, no time change |
-| serializer fix only | ~10,066 | ~31s | 0 modules, no time change |
-| axios barrel fix only | ~10,066 | ~31s | 0 modules, no time change |
-| All committed changes (no optimizePkgImports) | 10,068 | ~30.8s | +2 modules, no time change |
-
-> **Key finding**: Static analysis estimates were completely wrong. `optimizePackageImports` INCREASED modules (+213) instead of reducing them. Other changes had zero measurable impact on compilation time.
-
-### Assessment Conclusion
-
-**Phase 1 does not reduce compilation time.** The committed changes (import violation fixes, axios barrel fix) are code quality improvements but have no measurable effect on the dev compilation metric.
-
-**Why Phase 1 had no impact on compilation time**:
-1. **`optimizePackageImports` backfired**: In dev mode, this setting resolves individual sub-module files instead of the barrel, resulting in MORE module entries in webpack's graph. This is the opposite of the expected behavior. **Reverted — not committed.**
-2. **Import violation fixes don't reduce modules meaningfully**: The server modules pulled in by the violations were already being null-loaded (mongoose) or were lightweight (date-fns locale files only).
-3. **Barrel export removal had no measurable effect**: `export * from 'axios'` was unused, so removing it didn't change the module graph.
-4. **Compilation time is dominated by the sheer volume of 10,000+ client-side modules** that are legitimately needed by the `[[...path]]` catch-all page. Incremental import fixes cannot meaningfully reduce this.
-
-### Recommendation: Compilation Time Reduction Requires Architectural Changes
-
-The following approaches can actually reduce compilation time for `[[...path]]`:
-
-1. **Next.js 15 + `bundlePagesRouterDependencies`** — Changes how server dependencies are handled, potentially excluding thousands of modules from client compilation
-2. **Turbopack** — Rust-based bundler with 14x faster cold starts; handles the same 10,000 modules much faster
-3. **Route splitting** — Break `[[...path]]` into smaller routes so each compiles fewer modules on-demand
-
-**Key blockers for Next.js upgrade (Task 8.2)**:
-1. `next-superjson` SWC plugin compatibility — critical blocker
-2. React 19 peer dependency — manageable (Pages Router backward compat)
-3. `I18NextHMRPlugin` — webpack-specific; may need alternative
-
-**Decision**: Phase 1 committed changes are kept as code quality improvements (server/client boundary enforcement, dead code removal). Phase 2 evaluation is needed for actual compilation time reduction.
-
-## Phase 2: Module Graph Analysis and Dynamic Import Optimization (Task 8.1 continued)
-
-### Module Composition Analysis
-
-Client bundle module paths extracted from `.next/static/chunks/` — 6,822 unique modules total.
-
-**Top 10 module-heavy packages in [[...path]] compilation:**
-
-| Package | Modules | % of Total | Source |
-|---------|---------|-----------|--------|
-| lodash-es | 640 | 9.4% | Transitive via mermaid → chevrotain |
-| date-fns | 627 | 9.2% | Direct (barrel imports) + react-datepicker (v2) |
-| highlight.js | 385 | 5.6% | react-syntax-highlighter → CodeBlock |
-| refractor | 279 | 4.1% | react-syntax-highlighter → CodeBlock |
-| core-js | 227 | 3.3% | Next.js polyfills (not controllable via imports) |
-| @codemirror | 127 | 1.9% | Editor components |
-| lodash | 127 | 1.9% | Transitive via express-validator |
-| d3-array | 120 | 1.8% | Transitive via mermaid |
-| react-bootstrap-typeahead | 106 | 1.6% | Search/autocomplete UI |
-| **Top 10 total** | **2,752** | **40%** | |
-
-### Changes Applied
-
-1. **MermaidViewer → `next/dynamic({ ssr: false })`**
-   - Split `import * as mermaid from '~/features/mermaid'` into:
-     - Static: `remarkPlugin` + `sanitizeOption` from `~/features/mermaid/services` (lightweight, no npm mermaid)
-     - Dynamic: `MermaidViewer` via `next/dynamic` (loads mermaid npm + lodash-es + chevrotain on demand)
-   - SSR impact: None — client renderer only (`assert(isClient())`)
-
-2. **CodeBlock → `next/dynamic({ ssr: false })`**
-   - Removed static `import { CodeBlock }` from shared renderer (`src/services/renderer/renderer.tsx`)
-   - Added `DynamicCodeBlock` via `next/dynamic` in client renderer only
-   - SSR impact: Code blocks render without syntax highlighting during SSR (accepted trade-off)
-
-3. **date-fns barrel → subpath imports (12 files)**
-   - Converted all `import { ... } from 'date-fns'` to specific subpath imports
-   - e.g., `import { format } from 'date-fns/format'`
-   - Files: Comment.tsx, ShareLinkForm.tsx, ActivityListItem.tsx, DateRangePicker.tsx, FormattedDistanceDate.jsx, create-custom-axios.ts, activity.ts, user-activation.ts, forgot-password.js, thread-relation.ts, normalize-thread-relation-expired-at.ts, normalize-thread-relation-expired-at.integ.ts
-
-4. **core-js — no action possible**
-   - 227 modules come from Next.js automatic polyfill injection, not application imports
-   - Can only be reduced by `.browserslistrc` (targeting modern browsers) or Next.js 15+ upgrade
-
-### Measurement Results
-
-| Metric | Before | After | Change |
-|--------|--------|-------|--------|
-| Modules | 10,066 | 10,054 | -12 |
-| Compile time (run 1) | ~31s | 26.9s | -4.1s |
-| Compile time (run 2) | ~31s | 26.7s | -4.3s |
-| **Average compile time** | **~31s** | **~26.8s** | **-4.2s (14%)** |
-
-### Analysis
-
-- **Module count decreased only 12**: Dynamic imports still count as modules in the webpack graph, but they're compiled into separate chunks (lazy). The "10,054 modules" includes the lazy chunks' modules in the count.
-- **Compile time decreased ~14%**: The significant improvement suggests webpack's per-module overhead is not uniform — mermaid (with chevrotain parser generator) and react-syntax-highlighter (with highlight.js language definitions) are particularly expensive to compile despite their module count.
-- **date-fns subpath imports**: Contributed to the module count reduction but likely minimal time impact (consistent with Phase 1 findings).
-
-## Next.js v16 Upgrade: Post-Upgrade Measurement (2026-03-03)
-
-### Baseline vs Post-Upgrade (ChunkModuleStats)
-
-| Metric | Pre-upgrade (v15.5.12) | Post-upgrade (v16.1.6) | Delta | Tolerance | Status |
-|--------|----------------------|----------------------|-------|-----------|--------|
-| **initial** | 895 | 863 | -32 (-3.6%) | ±5% (850–940) | **PASS** |
-| **async-only** | 4,775 | 4,784 | +9 (+0.2%) | ±10% | **PASS** |
-| **total** | 5,670 | 5,647 | -23 (-0.4%) | ±10% | **PASS** |
-
-### Raw Output
-
-```
-[ChunkModuleStats] initial: 863, async-only: 4784, total: 5647
-```
-
-### Conclusion
-
-All module count metrics are within tolerance after the Next.js v16 upgrade. The initial module count actually **decreased** by 3.6% (895 → 863), indicating that v16's webpack bundling is slightly more efficient at tree-shaking or module deduplication. All custom webpack configuration (null-loader rules, superjson-ssr-loader, I18NextHMRPlugin, ChunkModuleStatsPlugin, source-map-loader) is fully preserved and functional.

+ 0 - 525
.kiro/specs/reduce-modules-loaded/design.md

@@ -1,525 +0,0 @@
-# Design Document: reduce-modules-loaded
-
-## Overview
-
-**Purpose**: This feature reduces the excessive module count (10,066 modules) compiled for the `[[...path]]` catch-all page in `apps/app`, improving developer experience through faster compilation times and a tighter development feedback loop.
-
-**Users**: GROWI developers working on `apps/app` will benefit from significantly reduced `turbo run dev` compilation times when accessing pages during local development.
-
-**Impact**: Changes the current build configuration, import patterns, and potentially the Next.js version to eliminate unnecessary module loading — particularly server-side modules leaking into the client compilation graph.
-
-### Goals
-- Reduce the `[[...path]]` page module count from 10,066 to a significantly lower number (target: measurable reduction with before/after metrics)
-- Identify and fix server-side module leakage into client bundle
-- Optimize barrel export patterns to prevent full module tree traversal
-- Evaluate and apply Next.js official configuration options for module reduction
-- If beneficial, upgrade Next.js to unlock `bundlePagesRouterDependencies` and `serverExternalPackages`
-
-### Non-Goals
-- Migration from Pages Router to App Router
-- Complete elimination of barrel exports across the entire codebase
-- Turbopack adoption in Phase 1 (deferred to Phase 2b due to webpack config incompatibility; see `research.md` — Turbopack Compatibility section)
-- Performance optimization beyond module count reduction (runtime perf, SSR latency, etc.)
-
-## Architecture
-
-### Existing Architecture Analysis
-
-GROWI `apps/app` uses Next.js 14 with Pages Router, Webpack, and the following relevant configuration:
-
-| Mechanism | Current State | Gap |
-|-----------|--------------|-----|
-| `optimizePackageImports` | 11 `@growi/*` packages | Not expanded to third-party or internal barrel-heavy modules |
-| null-loader (client exclusion) | `mongoose`, `dtrace-provider`, `mathjax-full` | 30+ server-only packages not covered |
-| `next/dynamic` + LazyLoaded pattern | Well-implemented for modal components | Already correct — not a primary contributor |
-| `@next/bundle-analyzer` | Installed, not routinely used | Useful for investigating module composition, but NOT for measuring dev compilation module count |
-| `bundlePagesRouterDependencies` | Not configured | Requires Next.js 15+ |
-| `serverExternalPackages` | Not configured | Requires Next.js 15+ |
-
-**Confirmed Import Violations**:
-1. `src/client/components/RecentActivity/ActivityListItem.tsx` → `~/server/util/locale-utils` (server boundary violation)
-2. `src/client/components/InAppNotification/.../PageBulkExportJobModelNotification.tsx` → `~/models/serializers/.../page-bulk-export-job.ts` → `import mongoose from 'mongoose'` (server module via serializer)
-
-**High-Impact Barrel Exports**:
-- `src/states/ui/editor/index.ts` — 7 wildcard re-exports
-- `src/features/page-tree/index.ts` — 3-level cascading barrels (15+ modules)
-- `src/utils/axios/index.ts` — re-exports entire axios library
-
-### Architecture Pattern & Boundary Map
-
-**Selected pattern**: Phased configuration-driven optimization with incremental structural fixes
-
-The optimization is divided into two phases. Phase 1 operates within the current Next.js 14 + Webpack architecture. Phase 2 evaluates and optionally executes a Next.js version upgrade based on Phase 1 results.
-
-```mermaid
-graph TB
-    subgraph Phase1[Phase 1 - v14 Optimizations]
-        A1[Bundle Analysis Baseline] --> A2[Expand optimizePackageImports]
-        A1 --> A3[Fix Import Violations]
-        A1 --> A4[Expand null-loader Rules]
-        A2 --> A5[Measure Module Count]
-        A3 --> A5
-        A4 --> A5
-        A5 --> A6[Refactor High-Impact Barrels]
-        A6 --> A7[Final Measurement]
-    end
-
-    subgraph Phase2[Phase 2 - Version Upgrade Evaluation]
-        B1[Evaluate Phase 1 Results]
-        B1 --> B2{Sufficient Reduction?}
-        B2 -->|Yes| B3[Document Results]
-        B2 -->|No| B4[Next.js 15 Upgrade]
-        B4 --> B5[Enable bundlePagesRouterDependencies]
-        B4 --> B6[Configure serverExternalPackages]
-        B4 --> B7[Resolve next-superjson Blocker]
-    end
-
-    A7 --> B1
-```
-
-**Domain boundaries**:
-- Build Configuration (`next.config.js`) — config-only changes, zero code risk
-- Import Graph (source files) — import path fixes, moderate risk
-- Framework Version (Next.js/React) — major upgrade, high risk
-
-**Existing patterns preserved**: Pages Router, `getServerSideProps`, Jotai/SWR state management, feature-based directory structure
-
-### Technology Stack
-
-| Layer | Choice / Version | Role in Feature | Notes |
-|-------|------------------|-----------------|-------|
-| Build System | Next.js ^14.2.35 (Phase 1) / ^15.x (Phase 2) | Module bundling, compilation | Webpack bundler |
-| Bundler | Webpack 5 (via Next.js) | Module resolution, tree-shaking | Turbopack deferred to Phase 2b |
-| Analysis | `@next/bundle-analyzer` | Baseline and verification measurement | Already installed |
-| Linting | Biome (existing) | Import boundary enforcement | Optional ESLint rule for server/client boundary |
-
-## System Flows
-
-### Phase 1: Optimization Flow
-
-```mermaid
-sequenceDiagram
-    participant Dev as Developer
-    participant DevServer as next dev
-    participant BA as Bundle Analyzer
-    participant Config as next.config.js
-    participant Src as Source Files
-
-    Note over Dev,DevServer: Baseline Measurement
-    Dev->>DevServer: turbo run dev + access page
-    DevServer-->>Dev: Compiled in 51.5s (10066 modules)
-
-    Note over Dev,BA: Investigation (optional)
-    Dev->>BA: ANALYZE=true pnpm run build
-    BA-->>Dev: Module composition treemap
-
-    Note over Dev,Src: Apply Optimizations
-    Dev->>Config: Expand optimizePackageImports
-    Dev->>Config: Add null-loader rules for server packages
-    Dev->>Src: Fix client to server import violations
-    Dev->>Src: Refactor high-impact barrel exports
-
-    Note over Dev,DevServer: Verification Measurement
-    Dev->>DevServer: turbo run dev + access page
-    DevServer-->>Dev: Compiled in Ys (M modules)
-```
-
-## Requirements Traceability
-
-| Requirement | Summary | Components | Interfaces | Flows |
-|-------------|---------|------------|------------|-------|
-| 1.1-1.4 | Next.js config research | ConfigResearch | — | Phase 1 |
-| 2.1-2.3 | Module count root cause analysis | DevCompilationMeasurement | — | Phase 1 |
-| 3.1-3.3 | Server-side leakage prevention | ImportViolationFix, NullLoaderExpansion | — | Phase 1 |
-| 3.4 | serverExternalPackages | NextjsUpgrade | next.config.js | Phase 2 |
-| 4.1-4.4 | Barrel export and package import optimization | OptimizePackageImportsExpansion, BarrelExportRefactor | — | Phase 1 |
-| 5.1-5.4 | Next.js version evaluation and upgrade | NextjsUpgrade | next.config.js | Phase 2 |
-| 6.1-6.3 | Compilation time and module count reduction | — (outcome) | — | Both |
-| 7.1-7.3 | Lazy loading verification | LazyLoadVerification | — | Phase 1 |
-
-## Components and Interfaces
-
-| Component | Domain | Intent | Req Coverage | Key Dependencies | Contracts |
-|-----------|--------|--------|--------------|-----------------|-----------|
-| DevCompilationMeasurement | Build | Measure dev module count as primary metric; bundle analyzer for investigation | 1.4, 2.1-2.3, 6.1 | Dev server log (P0), `@next/bundle-analyzer` (P1) | — |
-| OptimizePackageImportsExpansion | Build Config | Expand barrel file optimization coverage | 1.1, 4.3, 4.4 | `next.config.js` (P0) | Config |
-| NullLoaderExpansion | Build Config | Exclude additional server packages from client bundle | 3.1, 3.2 | `next.config.js` (P0) | Config |
-| ImportViolationFix | Source | Fix confirmed client-to-server import violations | 3.1, 3.2, 3.3 | Source files (P0) | — |
-| BarrelExportRefactor | Source | Refactor high-impact barrel exports to direct exports | 4.1, 4.2 | State/feature barrel files (P1) | — |
-| LazyLoadVerification | Build | Verify lazy-loaded components excluded from initial compilation | 7.1-7.3 | Bundle analysis output (P1) | — |
-| NextjsUpgrade | Framework | Evaluate and execute Next.js 15 upgrade | 5.1-5.4, 3.4 | next-superjson (P0 blocker), React 19 (P0) | Config |
-| ConfigResearch | Documentation | Document Next.js config options and applicability | 1.1-1.3 | — | — |
-
-### Build Configuration Domain
-
-#### DevCompilationMeasurement
-
-| Field | Detail |
-|-------|--------|
-| Intent | Measure dev compilation module count and time as the primary DX metric; use bundle analyzer as a supplementary investigation tool |
-| Requirements | 1.4, 2.1, 2.2, 2.3, 6.1 |
-
-**Responsibilities & Constraints**
-- Record dev compilation output (`Compiled /[[...path]] in Xs (N modules)`) as the **primary success metric**
-- Use `@next/bundle-analyzer` (`ANALYZE=true`) only as a **supplementary investigation tool** to understand which modules are included and trace import chains — NOT as the success metric
-- Establish baseline before any optimization, then measure after each step
-- Note: dev compilation does NOT tree-shake, so module count reflects the full dependency graph — this is exactly the metric we want to reduce
-
-**Important Distinction**:
-- `next dev` module count = modules webpack processes during on-demand compilation (no tree-shaking) → **this is what makes dev slow**
-- `next build` + ANALYZE = production bundle after tree-shaking → useful for investigation but does NOT reflect dev DX
-
-**Dependencies**
-- External: `@next/bundle-analyzer` — supplementary investigation tool (P1)
-- Inbound: Dev server compilation log — primary metric source (P0)
-
-**Contracts**: —
-
-**Implementation Notes**
-- Primary measurement: `turbo run dev` → access page → read `Compiled /[[...path]] in Xs (N modules)` from log
-- Clean `.next` directory before each measurement for consistent results
-- Supplementary: `ANALYZE=true pnpm run app:build` to inspect module composition when investigating specific leakage paths
-- Repeat measurement 3 times and take median to account for system variability
-
-#### OptimizePackageImportsExpansion
-
-| Field | Detail |
-|-------|--------|
-| Intent | Expand `optimizePackageImports` in `next.config.js` to cover barrel-heavy internal and third-party packages |
-| Requirements | 1.1, 4.3, 4.4 |
-
-**Responsibilities & Constraints**
-- Add packages identified by bundle analysis as barrel-heavy contributors
-- Maintain the existing 11 `@growi/*` entries
-- Identify third-party packages with barrel exports not in the auto-optimized list
-
-**Dependencies**
-- Outbound: `next.config.js` `experimental.optimizePackageImports` — config array (P0)
-- Inbound: BundleAnalysis — identifies which packages need optimization
-
-**Contracts**: Config [x]
-
-##### Configuration Interface
-
-Current configuration to extend:
-
-```typescript
-// next.config.js — experimental.optimizePackageImports
-// Existing entries preserved; new entries added based on bundle analysis
-const optimizePackageImports: string[] = [
-  // Existing @growi/* packages (11)
-  '@growi/core',
-  '@growi/editor',
-  '@growi/pluginkit',
-  '@growi/presentation',
-  '@growi/preset-themes',
-  '@growi/remark-attachment-refs',
-  '@growi/remark-drawio',
-  '@growi/remark-growi-directive',
-  '@growi/remark-lsx',
-  '@growi/slack',
-  '@growi/ui',
-  // Candidates for addition (validate with bundle analysis):
-  // - Third-party packages with barrel exports not in auto-list
-  // - Internal directories if supported by config
-];
-```
-
-**Implementation Notes**
-- Zero-risk config change — does not affect runtime behavior
-- Validate each addition with before/after module count measurement
-- Some packages may already be auto-optimized by Next.js (check against the auto-list in docs)
-
-#### NullLoaderExpansion
-
-| Field | Detail |
-|-------|--------|
-| Intent | Expand null-loader rules in webpack config to exclude additional server-only packages from client bundle |
-| Requirements | 3.1, 3.2 |
-
-**Responsibilities & Constraints**
-- Add null-loader rules for server-only packages confirmed to appear in client bundle by bundle analysis
-- Maintain existing rules for `dtrace-provider`, `mongoose`, `mathjax-full`
-- Only add packages that are actually present in the client bundle (verify with bundle analysis first)
-
-**Dependencies**
-- Outbound: `next.config.js` `webpack()` config — null-loader rules (P0)
-- Inbound: BundleAnalysis — confirms which server packages are in client bundle
-
-**Contracts**: Config [x]
-
-##### Configuration Interface
-
-```typescript
-// next.config.js — webpack config, client-side only (!options.isServer)
-// Existing patterns preserved; candidates added after bundle analysis verification
-const serverPackageExclusions: RegExp[] = [
-  /dtrace-provider/,   // existing
-  /mongoose/,          // existing
-  /mathjax-full/,      // existing
-  // Candidates (add only if confirmed in client bundle):
-  // /@elastic\/elasticsearch/,
-  // /passport/,
-  // /@aws-sdk\//,
-  // /@azure\//,
-  // /@google-cloud\//,
-  // /openai/,
-  // /@opentelemetry\//,
-  // /ldapjs/,
-  // /nodemailer/,
-  // /multer/,
-  // /socket\.io/,
-];
-```
-
-**Implementation Notes**
-- Must verify each package appears in client bundle before adding rule (avoid unnecessary config)
-- null-loader replaces module content with empty module — no runtime impact for correctly excluded packages
-- If a package is accidentally excluded that IS needed on client, it will cause runtime errors — test thoroughly
-
-### Source Code Domain
-
-#### ImportViolationFix
-
-| Field | Detail |
-|-------|--------|
-| Intent | Fix confirmed client-to-server import violations that cause server modules to leak into client bundle |
-| Requirements | 3.1, 3.2, 3.3 |
-
-**Responsibilities & Constraints**
-- Fix the confirmed import violation in `ActivityListItem.tsx` (`~/server/util/locale-utils`)
-- Fix the serializer import in `PageBulkExportJobModelNotification.tsx` (pulls in mongoose)
-- Ensure fixed modules maintain identical functionality
-- Establish a pattern for preventing future violations
-
-**Dependencies**
-- Inbound: BundleAnalysis — identifies import chains causing leakage (P0)
-
-**Contracts**: —
-
-##### Confirmed Violations to Fix
-
-| File | Violation | Fix Strategy |
-|------|-----------|-------------|
-| `src/client/components/RecentActivity/ActivityListItem.tsx` | Imports `getLocale` from `~/server/util/locale-utils` | Extract `getLocale` to a client-safe utility module (the function only needs `date-fns/locale`, no server deps) |
-| `src/client/components/InAppNotification/.../PageBulkExportJobModelNotification.tsx` | Imports serializer that has `import mongoose from 'mongoose'` | Split serializer: server-side `stringifySnapshot` stays in `~/models/`; client-side `parseSnapshot` moves to client-accessible module |
-| `src/stores/in-app-notification.ts` | Imports `~/models/serializers/.../user` | Verify this serializer is clean (confirmed: no mongoose import). Low priority. |
-
-**Implementation Notes**
-- The `getLocale` function itself has no server dependencies — only `date-fns/locale` and `@growi/core/dist/interfaces`. The file's location in `~/server/util/` is misleading; extracting it to `~/utils/` or `~/client/util/` resolves the violation.
-- For the serializer split: `parseSnapshot` is a pure JSON parsing function; `stringifySnapshot` uses mongoose and should remain server-only.
-- Consider adding a lint rule to prevent `src/client/**` or `src/components/**` from importing `src/server/**`.
-
-#### BarrelExportRefactor
-
-| Field | Detail |
-|-------|--------|
-| Intent | Refactor high-impact barrel export files to reduce unnecessary module tree traversal |
-| Requirements | 4.1, 4.2 |
-
-**Responsibilities & Constraints**
-- Refactor after verifying that `optimizePackageImports` expansion does not already resolve the issue
-- Prioritize files with highest module count impact (determined by bundle analysis)
-- Maintain backward compatibility — consumers should not need to change their import paths unless necessary
-
-**Dependencies**
-- Inbound: OptimizePackageImportsExpansion — determines which barrels are already optimized (P1)
-- Inbound: BundleAnalysis — quantifies barrel impact (P1)
-
-**Contracts**: —
-
-##### Target Barrel Files (Priority Order)
-
-| File | Issue | Refactor Strategy |
-|------|-------|-------------------|
-| `src/utils/axios/index.ts` | `export * from 'axios'` re-exports entire library | Replace with specific named exports used by consumers |
-| `src/states/ui/editor/index.ts` | 7 wildcard `export *` | Convert to named re-exports; or verify `optimizePackageImports` handles it |
-| `src/features/page-tree/index.ts` | 3-level cascading barrel (15+ modules) | Flatten to single-level named exports; or consumers import directly from submodules |
-| `src/states/page/index.ts` | 2 wildcard + named exports | Convert to named re-exports if still problematic after config optimization |
-
-**Implementation Notes**
-- Attempt `optimizePackageImports` expansion first — if it handles barrel files for `@growi/*` packages effectively, many of these refactors become unnecessary
-- For `utils/axios/index.ts`, the `export * from 'axios'` pattern is universally problematic; this should be fixed regardless of other optimizations
-- Barrel refactoring may require updating import paths across many files — use IDE refactoring tools and verify with `turbo run lint:typecheck`
-
-### Build Verification Domain
-
-#### LazyLoadVerification
-
-| Field | Detail |
-|-------|--------|
-| Intent | Verify that lazy-loaded components are correctly excluded from initial page compilation |
-| Requirements | 7.1, 7.2, 7.3 |
-
-**Responsibilities & Constraints**
-- Verify the existing `*LazyLoaded` pattern (dynamic.tsx + useLazyLoader) does not contribute to initial module count
-- Confirm `index.ts` files in lazy-loaded component directories only re-export from `dynamic.tsx`
-- Check bundle analysis output for any lazy-loaded component modules in the initial bundle
-
-**Dependencies**
-- Inbound: BundleAnalysis — verifies exclusion from initial bundle (P1)
-
-**Contracts**: —
-
-**Implementation Notes**
-- Gap analysis confirms the LazyLoaded pattern is already well-implemented
-- This component is primarily a verification step, not a fix
-- If any lazy-loaded components are found in the initial bundle, the fix follows the existing `dynamic.tsx` pattern
-
-### Framework Upgrade Domain (Phase 2)
-
-#### NextjsUpgrade
-
-| Field | Detail |
-|-------|--------|
-| Intent | Evaluate and optionally execute Next.js 15 upgrade to unlock `bundlePagesRouterDependencies` and `serverExternalPackages` |
-| Requirements | 5.1, 5.2, 5.3, 5.4, 3.4 |
-
-**Responsibilities & Constraints**
-- Only proceed if Phase 1 results indicate insufficient module reduction
-- Address the `next-superjson` compatibility blocker before upgrading
-- Use the official `@next/codemod` for automated migration
-- Maintain React 18 compatibility with Pages Router (backward compat available in v15)
-
-**Dependencies**
-- External: `next-superjson` — SWC plugin compatibility (P0 blocker)
-- External: React 19 — peer dependency (P0, but backward compat available)
-- External: `@next/codemod` — migration automation (P1)
-
-**Contracts**: Config [x]
-
-##### Configuration Interface (Post-Upgrade)
-
-```typescript
-// next.config.js — New v15 options
-const nextConfig = {
-  // Enable automatic server-side dependency bundling for Pages Router
-  bundlePagesRouterDependencies: true,
-  // Exclude heavy server-only packages from bundling
-  serverExternalPackages: [
-    'mongoose',
-    // Additional packages based on bundle analysis
-  ],
-};
-```
-
-##### Known Blockers
-
-| Blocker | Severity | Mitigation |
-|---------|----------|------------|
-| `next-superjson` SWC plugin broken in v15 | Critical | **Resolved** — custom webpack loader (`superjson-ssr-loader.js`) replaces the SWC plugin with a simple regex-based source transform; see SuperJSON Migration section below |
-| `I18NextHMRPlugin` (webpack plugin) | Medium | Only affects dev HMR for i18n; can use `--webpack` flag for dev |
-| React 19 peer dependency | Low | Pages Router has React 18 backward compat in v15 |
-| `@next/font` removal | Low | Codemod available; switch to `next/font` |
-
-##### SuperJSON Migration: Custom Webpack Loader Approach
-
-The `next-superjson` SWC plugin is replaced by a custom webpack loader that achieves the same transparent auto-wrapping of `getServerSideProps` without any SWC/Babel dependency.
-
-**Architecture**:
-
-```
-┌─────────────────────────────────────────────────────────────────┐
-│ Build Time (webpack)                                            │
-│                                                                 │
-│  .page.tsx files ──► superjson-ssr-loader.js ──► bundled output │
-│                      (auto-wraps getServerSideProps             │
-│                       with withSuperJSONProps)                  │
-└─────────────────────────────────────────────────────────────────┘
-
-┌─────────────────────────────────────────────────────────────────┐
-│ Runtime                                                         │
-│                                                                 │
-│  Server: getServerSideProps → superjson.serialize(props)        │
-│  Client: _app.page.tsx → deserializeSuperJSONProps(pageProps)   │
-└─────────────────────────────────────────────────────────────────┘
-```
-
-**Components**:
-
-| File | Role |
-|------|------|
-| `src/utils/superjson-ssr-loader.js` | Webpack loader — regex-based source transform that auto-wraps `getServerSideProps` exports |
-| `src/pages/utils/superjson-ssr.ts` | Runtime helpers — `withSuperJSONProps()` (server) and `deserializeSuperJSONProps()` (client) |
-| `_app.page.tsx` | Centralized client-side deserialization via `deserializeSuperJSONProps()` |
-| `next.config.js` | Loader registration targeting `.page.{ts,tsx}` files |
-
-**Why this approach over per-page wrapping**:
-- Zero per-page file changes (38 fewer files modified vs manual wrapping)
-- New pages automatically get superjson serialization without manual wrapping
-- Closer to the original `next-superjson` DX (config-only, transparent to page authors)
-- Webpack loader API is stable across Next.js versions — no SWC ABI fragility
-
-**Why not `next-superjson` v1.0.8**:
-- v1.0.8 achieves "v15 support" by pinning `@swc/core@1.4.17` (March 2024) and running a separate SWC compilation pass — fragile binary pinning with double compilation
-- Depends on unmaintained `next-superjson-plugin` v0.6.3 WASM binary
-- See `research.md` for detailed assessment
-
-**Implementation Notes**
-- Run codemod first: `npx @next/codemod@canary upgrade latest`
-- Test with `--webpack` flag to isolate bundler-related issues from framework issues
-- The `bundlePagesRouterDependencies: true` setting is the highest-value v15 feature for this spec — it automatically bundles server-side deps, which combined with `serverExternalPackages` provides fine-grained control
-
-## Testing Strategy
-
-### Verification Tests (Module Count — Primary DX Metric)
-- **Primary**: Run `turbo run dev`, access page, record `Compiled /[[...path]] in Xs (N modules)` from log before and after each optimization step
-- **Supplementary**: Run `ANALYZE=true pnpm run app:build` only when investigating specific module composition (e.g., tracing which server modules appear in client bundle)
-- Clean `.next` directory before each measurement; repeat 3 times, take median
-
-### Regression Tests
-- `turbo run lint:typecheck --filter @growi/app` — verify no type errors from import changes
-- `turbo run lint:biome --filter @growi/app` — verify no lint violations
-- `turbo run test --filter @growi/app` — verify all existing tests pass
-- `turbo run build --filter @growi/app` — verify production build succeeds
-- Manual smoke test: access `[[...path]]` page and verify all functionality works (page rendering, editing, navigation, modals)
-
-### Phase 2 Additional Tests
-- All Phase 1 tests
-- `npx @next/codemod@canary upgrade latest --dry` — preview upgrade changes
-- Test superjson serialization: verify `getServerSideProps` data correctly serialized/deserialized for all page routes
-- Test i18n HMR: verify locale changes reflect in dev mode (may degrade if I18NextHMRPlugin is removed)
-
-## Performance & Scalability
-
-**Target Metrics**:
-- **Primary (DX metric)**: Dev compilation module count for `[[...path]]` page (baseline: 10,066 modules)
-- **Secondary (DX metric)**: Dev compilation time for `[[...path]]` page (baseline: 51.5s)
-- **Supplementary (investigation only)**: Production bundle composition via `@next/bundle-analyzer`
-
-> **Important**: The primary metric is the dev compilation log, NOT the production bundle analyzer. Dev compilation does not tree-shake, so the module count directly reflects what makes development slow. Production bundle analysis is useful for tracing import chains but does not represent the dev experience.
-
-**Measurement Protocol**:
-1. Clean `.next` directory (`rm -rf apps/app/.next`)
-2. Run `turbo run dev`
-3. Navigate to `/` or any wiki page path in the browser
-4. Record `Compiled /[[...path]] in Xs (N modules)` from the terminal log
-5. Repeat 3 times, take median value
-6. Record results in a comparison table for each optimization step
-
-## Supporting References
-
-### Server-Only Package Candidates for null-loader
-
-From `apps/app/package.json`, the following packages are server-only and should be excluded from client bundle if they appear there:
-
-| Category | Packages |
-|----------|----------|
-| Database | `mongoose`, `mongodb`, `mongoose-gridfs`, `mongoose-paginate-v2`, `mongoose-unique-validator` |
-| Search | `@elastic/elasticsearch7`, `@elastic/elasticsearch8`, `@elastic/elasticsearch9` |
-| Auth | `passport`, `passport-github2`, `passport-google-oauth20`, `passport-ldapauth`, `passport-saml` |
-| Cloud Storage | `@aws-sdk/client-s3`, `@aws-sdk/s3-request-presigner`, `@azure/storage-blob`, `@google-cloud/storage` |
-| AI | `openai`, `@azure/openai` |
-| Identity | `@azure/identity`, `ldapjs` |
-| File Upload | `multer`, `multer-autoreap` |
-| Email | `nodemailer`, `nodemailer-ses-transport` |
-| Real-time | `socket.io`, `y-socket.io`, `y-mongodb-provider` |
-| Session/Cache | `connect-redis`, `redis` |
-| Observability | `@opentelemetry/*` (8 packages) |
-
-> Only add null-loader rules for packages confirmed present in the client bundle by bundle analysis.
-
-### Auto-Optimized Packages (No Need to Add to optimizePackageImports)
-
-The following packages are automatically optimized by Next.js and should NOT be added to the config:
-`lucide-react`, `date-fns`, `lodash-es`, `ramda`, `antd`, `react-bootstrap`, `ahooks`, `@ant-design/icons`, `@headlessui/react`, `@headlessui-float/react`, `@heroicons/react/*`, `@visx/visx`, `@tremor/react`, `rxjs`, `@mui/material`, `@mui/icons-material`, `recharts`, `react-use`, `@material-ui/*`, `@tabler/icons-react`, `mui-core`, `react-icons/*`, `effect`, `@effect/*`

+ 0 - 240
.kiro/specs/reduce-modules-loaded/gap-analysis.md

@@ -1,240 +0,0 @@
-# Gap Analysis: reduce-modules-loaded
-
-## 1. Current State Investigation
-
-### Key Files & Architecture
-
-| Asset | Path | Role |
-|-------|------|------|
-| Next.js config | `apps/app/next.config.js` | Build config with webpack rules, transpilePackages, optimizePackageImports |
-| Catch-all page | `apps/app/src/pages/[[...path]]/index.page.tsx` | Main page route — 10,066 modules on compilation |
-| Server-side props | `apps/app/src/pages/[[...path]]/server-side-props.ts` | getServerSideProps logic |
-| Common props | `apps/app/src/pages/common-props.ts` | Shared server-side props |
-| Transpile utils | `apps/app/src/utils/next.config.utils.js` | Dynamic ESM package discovery for transpilePackages |
-| Package.json | `apps/app/package.json` | 193 dependencies (32+ server-only) |
-
-### Existing Optimization Mechanisms
-
-1. **`optimizePackageImports`** — configured for 11 `@growi/*` packages
-2. **null-loader** — excludes `dtrace-provider`, `mongoose`, `mathjax-full` from client bundle
-3. **`next/dynamic`** — used for 6+ components with `{ ssr: false }`
-4. **LazyLoaded pattern** — `*LazyLoaded` wrapper components use `useLazyLoader` hook with dynamic `import()` — correctly defers actual component loading
-5. **`@next/bundle-analyzer`** — already installed but not routinely used
-
-### Conventions Observed
-
-- **Pages Router** with `getServerSideProps` (not App Router)
-- **next-superjson** for serialization in SSR
-- `pageExtensions: ['page.tsx', 'page.ts', 'page.jsx', 'page.js']`
-- Feature-based organization in `src/features/`
-- State management: Jotai atoms in `src/states/`, SWR hooks in `src/stores/`
-
----
-
-## 2. Requirement-to-Asset Map
-
-### Requirement 1: Next.js Official Configuration Research
-
-| Need | Status | Notes |
-|------|--------|-------|
-| `optimizePackageImports` evaluation | **Partially Exists** | Configured for 11 @growi/* packages; not expanded to cover barrel-heavy third-party deps |
-| `bundlePagesRouterDependencies` evaluation | **Missing** | Not configured; requires Next.js 15+ |
-| `serverExternalPackages` evaluation | **Missing** | Not configured; requires Next.js 15+ |
-| Turbopack evaluation | **Missing** | Currently using Webpack; Turbopack stable in Next.js 15+ |
-| Bundle analysis tooling | **Exists** | `@next/bundle-analyzer` installed; `next experimental-analyze` available in v16.1+ |
-
-### Requirement 2: Module Count Root Cause Analysis
-
-| Need | Status | Notes |
-|------|--------|-------|
-| Bundle analysis tooling | **Exists** | `@next/bundle-analyzer` already in `next.config.js` (ANALYZE env var) |
-| Server-side module identification | **Gap** | No automated mechanism to detect server module leakage |
-| Barrel export impact quantification | **Gap** | No tooling to measure per-barrel module overhead |
-
-### Requirement 3: Server-Side Module Leakage Prevention
-
-| Need | Status | Notes |
-|------|--------|-------|
-| null-loader for mongoose | **Exists** | Already configured |
-| null-loader for other server packages | **Gap — CRITICAL** | 30+ server-only packages NOT excluded (see below) |
-| Client → server import detection | **Gap** | No ESLint rule or build-time check |
-| `serverExternalPackages` | **Gap** | Requires Next.js 15+ |
-
-**Confirmed Leakage Paths:**
-
-1. **`src/client/components/RecentActivity/ActivityListItem.tsx`** → `~/server/util/locale-utils` → pulls in `^/config/i18next.config` (lightweight, but breaks server/client boundary)
-2. **`src/client/components/InAppNotification/ModelNotification/PageBulkExportJobModelNotification.tsx`** → `~/models/serializers/.../page-bulk-export-job.ts` → **`import mongoose from 'mongoose'`** → pulls in entire mongoose + MongoDB driver (but null-loader should catch this on client)
-3. **`src/stores/in-app-notification.ts`** → `~/models/serializers/.../user.ts` (clean — no mongoose import)
-
-**Server-Only Packages Missing from null-loader:**
-
-| Package | Type | Estimated Module Impact |
-|---------|------|----------------------|
-| `@elastic/elasticsearch*` (v7/v8/v9) | Search | High |
-| `passport`, `passport-*` (5 packages) | Auth | Medium |
-| `@aws-sdk/*` | Cloud storage | High |
-| `@azure/*` (3 packages) | Cloud + AI | High |
-| `@google-cloud/storage` | Cloud storage | Medium |
-| `openai`, `@azure/openai` | AI | Medium |
-| `@opentelemetry/*` (8 packages) | Observability | Medium |
-| `ldapjs` | Auth | Low |
-| `nodemailer*` | Email | Low |
-| `multer*` | File upload | Low |
-| `redis`, `connect-redis` | Session | Low |
-| `socket.io` | Real-time | Medium |
-
-> **Note:** Whether these packages actually get pulled into the client bundle depends on whether any client-reachable import chain references them. The null-loader for mongoose suggests this category of leakage has been observed before.
-
-### Requirement 4: Barrel Export and Package Import Optimization
-
-| Need | Status | Notes |
-|------|--------|-------|
-| Expand `optimizePackageImports` | **Gap** | Only 11 @growi/* packages; missing third-party barrel-heavy deps |
-| Eliminate `export *` in states/ | **Gap** | 7+ barrel export files in `src/states/` with `export *` patterns |
-| Eliminate `export *` in features/ | **Gap** | `features/page-tree/index.ts` cascades to 15+ modules |
-| Direct imports instead of barrel | **Gap** | Requires refactoring import paths across codebase |
-
-**High-Impact Barrel Export Files:**
-
-| File | Wildcard Exports | Cascading Depth |
-|------|-----------------|----------------|
-| `src/states/ui/editor/index.ts` | 7 `export *` | 1 level |
-| `src/features/page-tree/index.ts` | 3 `export *` | 3 levels → 15+ modules |
-| `src/features/page-tree/hooks/_inner/index.ts` | 8 `export *` | 1 level |
-| `src/states/page/index.ts` | 2 `export *` + named | 1 level |
-| `src/utils/axios/index.ts` | `export * from 'axios'` | Re-exports entire library |
-
-### Requirement 5: Next.js Version Evaluation and Upgrade
-
-| Need | Status | Notes |
-|------|--------|-------|
-| Current version: Next.js `^14.2.35` | **Exists** | Pages Router architecture |
-| Upgrade to v15 evaluation | **Research Needed** | Breaking changes, React 19 dependency, `bundlePagesRouterDependencies` |
-| Upgrade to v16 evaluation | **Research Needed** | Turbopack default, experimental-analyze tool |
-| Migration effort assessment | **Research Needed** | 30+ page files, custom webpack config, superjson plugin |
-
-### Requirement 6: Compilation Time and Module Count Reduction
-
-| Need | Status | Notes |
-|------|--------|-------|
-| Baseline measurement | **Exists** | 10,066 modules / 51.5s for `[[...path]]` |
-| Before/after metrics framework | **Gap** | No automated benchmarking in CI |
-| Functional regression testing | **Exists** | Vitest test suite, Turbo test pipeline |
-
-### Requirement 7: Lazy Loading and Dynamic Import Verification
-
-| Need | Status | Notes |
-|------|--------|-------|
-| LazyLoaded wrapper pattern | **Exists — Well Designed** | `dynamic.tsx` files use `useLazyLoader` with dynamic `import()` |
-| Index re-export pattern | **Exists — Clean** | `index.ts` files only re-export from `dynamic.tsx`, not the actual component |
-| Verification tooling | **Gap** | No automated check that lazy-loaded components stay out of initial bundle |
-
-**Good News:** The `*LazyLoaded` pattern is already well-implemented:
-```
-index.ts → exports from dynamic.tsx → useLazyLoader(() => import('./ActualComponent'))
-```
-The actual component is only loaded when the trigger condition is met. This is NOT a major contributor to the 10,066 module count.
-
----
-
-## 3. Implementation Approach Options
-
-### Option A: Configuration-First (No Version Upgrade)
-
-**Approach:** Maximize optimizations within Next.js 14 + Webpack
-
-1. Expand `optimizePackageImports` to cover more barrel-heavy packages
-2. Add null-loader rules for additional server-only packages
-3. Fix confirmed client → server import violations
-4. Refactor critical barrel exports (`states/ui/editor`, `features/page-tree`, `utils/axios`)
-
-**Trade-offs:**
-- ✅ No breaking changes, lowest risk
-- ✅ Immediately measurable impact
-- ✅ Each change is independently verifiable
-- ❌ Limited by Webpack's tree-shaking capabilities
-- ❌ `bundlePagesRouterDependencies` and `serverExternalPackages` unavailable
-- ❌ No Turbopack benefits (automatic import optimization, faster HMR)
-
-### Option B: Next.js 15 Upgrade + Configuration
-
-**Approach:** Upgrade to Next.js 15, then apply v15-specific optimizations
-
-1. Upgrade Next.js 14 → 15 (address breaking changes)
-2. Enable `bundlePagesRouterDependencies` + `serverExternalPackages`
-3. Expand `optimizePackageImports`
-4. Fix client → server import violations
-5. Optionally enable Turbopack for dev
-
-**Trade-offs:**
-- ✅ Unlocks `bundlePagesRouterDependencies` and `serverExternalPackages`
-- ✅ Turbopack available (auto-optimizes imports, 14x faster cold start)
-- ✅ Better tree-shaking in Webpack 5 improvements
-- ❌ React 19 dependency — breaking change risk across all components
-- ❌ `next-superjson` compatibility unknown
-- ❌ Medium-to-high migration effort (30+ page files, custom webpack config)
-- ❌ Risk of regressions across authentication, i18n, etc.
-
-### Option C: Hybrid — Configuration-First, Then Upgrade (Recommended)
-
-**Approach:** Phase 1 optimizes within v14; Phase 2 evaluates and executes upgrade
-
-**Phase 1 (Low Risk, Immediate Impact):**
-1. Run `@next/bundle-analyzer` to establish baseline and identify top contributors
-2. Expand `optimizePackageImports` list
-3. Add null-loader rules for confirmed server-only packages in client bundle
-4. Fix client → server import violations (1 confirmed: `ActivityListItem.tsx`)
-5. Refactor high-impact barrel exports
-6. Measure before/after module count
-
-**Phase 2 (Higher Risk, Longer Term):**
-1. Evaluate Next.js 15/16 upgrade feasibility based on Phase 1 findings
-2. If module count reduction from Phase 1 is insufficient, proceed with upgrade
-3. Enable `bundlePagesRouterDependencies` + `serverExternalPackages`
-4. Evaluate Turbopack adoption for dev mode
-
-**Trade-offs:**
-- ✅ Quick wins first — validates approach before committing to upgrade
-- ✅ Phase 1 findings inform Phase 2 decisions
-- ✅ Incremental risk management
-- ❌ More total effort if upgrade is ultimately needed
-- ❌ Two phases of testing/validation
-
----
-
-## 4. Effort & Risk Assessment
-
-| Requirement | Effort | Risk | Justification |
-|-------------|--------|------|---------------|
-| Req 1: Config Research | S (1-2 days) | Low | Docs research + local testing |
-| Req 2: Root Cause Analysis | S (1-2 days) | Low | Run bundle analyzer, document findings |
-| Req 3: Server-Side Leakage Fix | M (3-5 days) | Medium | Import chain fixes, null-loader expansion, testing |
-| Req 4: Barrel Export Optimization | M (3-5 days) | Medium | Widespread refactoring of import paths |
-| Req 5: Next.js Upgrade | L-XL (1-3 weeks) | High | React 19, breaking changes, 30+ pages, plugin compat |
-| Req 6: Module Count Reduction | — | — | Outcome of Reqs 1-5 |
-| Req 7: Lazy Loading Verification | S (1 day) | Low | Already well-implemented, needs verification only |
-
-**Overall Effort:** M-L (depending on whether upgrade is pursued)
-**Overall Risk:** Medium (Phase 1) / High (if Next.js upgrade)
-
----
-
-## 5. Research Items for Design Phase
-
-1. **Next.js 15 breaking changes inventory** — Full compatibility assessment with GROWI's Pages Router, `next-superjson`, custom webpack config
-2. **Turbopack Pages Router support** — Confirm Turbopack works with `getServerSideProps`, `pageExtensions`, custom webpack rules
-3. **null-loader effectiveness validation** — Confirm which server packages actually appear in client bundle (some may already be tree-shaken)
-4. **`bundlePagesRouterDependencies` impact measurement** — Test with GROWI-like setup to measure actual module reduction
-5. **ESLint boundary rule** — Evaluate `eslint-plugin-import` or `@nx/enforce-module-boundaries` for preventing client → server imports
-
----
-
-## 6. Recommendations for Design Phase
-
-1. **Preferred approach:** Option C (Hybrid) — start with configuration-first optimizations, evaluate upgrade based on results
-2. **First action:** Run `ANALYZE=true pnpm run build` to generate bundle analysis report — this will immediately reveal the top module contributors
-3. **Quick wins to prioritize:**
-   - Expand `optimizePackageImports` (zero-risk config change)
-   - Fix `ActivityListItem.tsx` server import (1 file change)
-   - Verify null-loader coverage for mongoose is effective
-4. **Defer:** Next.js upgrade decision until after Phase 1 metrics are collected

+ 0 - 89
.kiro/specs/reduce-modules-loaded/requirements.md

@@ -1,89 +0,0 @@
-# Requirements Document
-
-## Introduction
-
-When running `turbo run dev` for `apps/app` and accessing a page, Next.js compiles the `[[...path]]` catch-all route with over 10,000 modules (`Compiled /[[...path]] in 51.5s (10066 modules)`). This is excessive and likely caused by unnecessary server-side modules being pulled into the client bundle, barrel export patterns causing full module tree traversal, and suboptimal tree-shaking. The goal is to investigate root causes, identify effective Next.js configuration options from official documentation, reduce the module count significantly, and improve developer experience (DX) by reducing compilation time. If a Next.js major upgrade is needed to achieve these goals, it should be pursued.
-
-## Requirements
-
-### Requirement 1: Next.js Official Configuration Research
-
-**Objective:** As a developer, I want to research and identify effective Next.js configuration options from official documentation that can reduce the module count and compilation time, so that I can apply proven optimization strategies.
-
-#### Acceptance Criteria
-
-1. The research shall evaluate the following Next.js configuration options for applicability to the GROWI Pages Router architecture:
-   - `optimizePackageImports` — barrel file optimization for packages with hundreds of re-exports (documented to reduce modules by up to 90% for libraries like `@material-ui/icons`: 11,738 → 632 modules)
-   - `bundlePagesRouterDependencies` — automatic server-side dependency bundling for Pages Router (matches App Router default behavior)
-   - `serverExternalPackages` — opt-out specific heavy/native dependencies from server-side bundling to use native Node.js `require`
-   - Turbopack adoption — automatic import optimization without manual `optimizePackageImports` config, with 14x faster cold starts and 28x faster HMR vs Webpack
-2. The research shall document which options are applicable to the current GROWI setup (Pages Router, Next.js 14, Webpack) and which require a version upgrade.
-3. The research shall produce a prioritized list of configuration changes with estimated impact, based on official Next.js benchmarks and the GROWI-specific module analysis.
-4. Where Next.js provides built-in bundle analysis tools (`@next/bundle-analyzer`, `next experimental-analyze`), the research shall evaluate their use for identifying the top module contributors in the `[[...path]]` page.
-
-### Requirement 2: Module Count Root Cause Analysis
-
-**Objective:** As a developer, I want to understand why the `[[...path]]` page loads 10,000+ modules during compilation, so that I can identify actionable optimization targets.
-
-#### Acceptance Criteria
-
-1. When the developer runs a Next.js bundle analysis on the `[[...path]]` page, the GROWI build system shall produce a report identifying the top module contributors by count and size.
-2. The GROWI build system shall identify server-side-only modules (e.g., mongoose, Express models, migration scripts) that are incorrectly included in the client-side compilation of the `[[...path]]` page.
-3. When barrel export files (index.ts with `export *`) are analyzed, the build analysis shall identify which barrel exports cause unnecessary module traversal and quantify the additional modules pulled in by each.
-
-### Requirement 3: Server-Side Module Leakage Prevention
-
-**Objective:** As a developer, I want server-side modules to be excluded from client-side compilation, so that the module count is reduced and compilation time improves.
-
-#### Acceptance Criteria
-
-1. The GROWI application shall ensure that server-side modules (Mongoose models, Express routes, migration scripts, server services) are not included in the client-side module graph of any Next.js page.
-2. When `getServerSideProps` or server-side utility functions import server-only modules, the Next.js build system shall tree-shake those imports from the client bundle.
-3. If a shared module inadvertently imports server-side code, the build system shall detect and report the import chain that causes the leakage.
-4. Where `serverExternalPackages` is available (Next.js 15+), the GROWI build system shall use it to exclude heavy server-only packages (e.g., mongoose, sharp) from server-side bundling.
-
-### Requirement 4: Barrel Export and Package Import Optimization
-
-**Objective:** As a developer, I want to reduce the impact of barrel exports on module resolution, so that importing a single hook or component does not pull in the entire module subtree.
-
-#### Acceptance Criteria
-
-1. When a single export is imported from a state module (e.g., `~/states/page`), the build system shall resolve only the necessary module and its direct dependencies, not the entire barrel export tree.
-2. The GROWI application shall avoid `export * from` patterns in high-traffic import paths (states, stores, features) where tree-shaking is ineffective.
-3. Where `optimizePackageImports` is configured in `next.config.js`, the GROWI build system shall include all internal `@growi/*` packages and high-impact third-party packages that use barrel exports.
-4. The GROWI build system shall expand the existing `optimizePackageImports` list beyond the current 11 `@growi/*` packages to cover additional barrel-heavy dependencies identified in the module analysis.
-
-### Requirement 5: Next.js Version Evaluation and Upgrade
-
-**Objective:** As a developer, I want to evaluate whether upgrading Next.js (from v14 to v15 or later) provides meaningful module optimization improvements, so that I can make an informed upgrade decision.
-
-#### Acceptance Criteria
-
-1. The evaluation shall document which Next.js 15+ features are relevant to reducing module count, specifically:
-   - Turbopack as stable/default bundler (automatic import optimization, no `optimizePackageImports` config needed)
-   - `bundlePagesRouterDependencies` option (automatic server-side dependency bundling for Pages Router)
-   - `serverExternalPackages` (stable rename of `serverComponentsExternalPackages`)
-   - Improved tree-shaking and module resolution
-2. If the Next.js upgrade is determined to be beneficial, the GROWI application shall be upgraded with all breaking changes addressed.
-3. When the upgrade is performed, the GROWI application shall pass all existing tests and build successfully.
-4. If the upgrade is determined to be not beneficial or too risky, the evaluation shall document the reasoning and alternative approaches achievable on the current version.
-
-### Requirement 6: Compilation Time and Module Count Reduction
-
-**Objective:** As a developer, I want the `[[...path]]` page compilation to be significantly faster with fewer modules, so that the development feedback loop is improved.
-
-#### Acceptance Criteria
-
-1. After optimizations, the `[[...path]]` page shall compile with significantly fewer modules than the current 10,066 (target: measurable reduction documented with before/after metrics).
-2. The GROWI application shall maintain full functional correctness after module reduction — no features shall be broken or missing.
-3. While in development mode, the GROWI application shall not show any new runtime errors or warnings introduced by the module optimization changes.
-
-### Requirement 7: Lazy Loading and Dynamic Import Verification
-
-**Objective:** As a developer, I want lazy-loaded components to be truly excluded from the initial compilation, so that they do not contribute to the module count until actually needed.
-
-#### Acceptance Criteria
-
-1. When a component is declared as "lazy loaded" (e.g., `*LazyLoaded` components), the GROWI build system shall not include that component's full dependency tree in the initial page compilation.
-2. The GROWI application shall use `next/dynamic` with `{ ssr: false }` for all heavy modal components that are not needed on initial page render.
-3. Where a lazy-loaded component wrapper (`index.ts`) re-exports the actual component statically, the GROWI application shall restructure the export to prevent static resolution of the full component tree.

+ 0 - 295
.kiro/specs/reduce-modules-loaded/research.md

@@ -1,295 +0,0 @@
-# Research & Design Decisions
-
-## Summary
-- **Feature**: `reduce-modules-loaded`
-- **Discovery Scope**: Complex Integration (build system optimization + potential major framework upgrade)
-- **Key Findings**:
-  - `next-superjson` SWC plugin is broken in Next.js 15 — critical blocker for upgrade
-  - Turbopack (default in v16) does NOT support `webpack()` config — GROWI's null-loader rules and I18NextHMRPlugin are incompatible
-  - `optimizePackageImports` expansion and barrel export refactoring are zero-risk optimizations achievable on current v14
-  - `bundlePagesRouterDependencies` + `serverExternalPackages` require Next.js 15+ but provide significant server-side bundling control
-
-## Research Log
-
-### Next.js 15 Breaking Changes for Pages Router
-- **Context**: Evaluating whether Next.js 15 upgrade is feasible for GROWI's Pages Router architecture
-- **Sources Consulted**: [Next.js v15 Upgrade Guide](https://nextjs.org/docs/app/guides/upgrading/version-15)
-- **Findings**:
-  - React 19 is minimum requirement, but backward compatibility for React 18 is available with Pages Router
-  - `bundlePagesRouterDependencies` is now stable (renamed from `experimental.bundlePagesExternals`)
-  - `serverExternalPackages` is now stable (renamed from `experimental.serverComponentsExternalPackages`)
-  - Async Request APIs change (`cookies`, `headers`, etc.) — App Router only, does NOT affect Pages Router
-  - `@next/font` package removed → must use `next/font` (codemod available)
-  - Caching defaults changed (fetch, Route Handlers) — primarily App Router concern
-- **Implications**:
-  - Pages Router migration is relatively low-impact for the async API changes
-  - The main upgrade value is `bundlePagesRouterDependencies` + `serverExternalPackages`
-  - React 18 backward compat means component migration can be gradual
-
-### next-superjson Compatibility with Next.js 15
-- **Context**: GROWI uses `next-superjson` for SSR serialization in `getServerSideProps`
-- **Sources Consulted**: [next-superjson GitHub](https://github.com/remorses/next-superjson), web search results
-- **Findings**:
-  - `next-superjson-plugin` (SWC-based) is broken in Next.js 15 due to SWC version incompatibility
-  - The `next-superjson` wrapper (used by GROWI — see `withSuperjson()` in `next.config.js`) may have the same issue
-  - GROWI registers custom ObjectId transformer via `superjson.registerCustom`
-  - Alternative: Manual superjson serialization in `getServerSideProps` without the plugin
-- **Implications**:
-  - **Critical blocker** for Next.js 15 upgrade
-  - Must either find a compatible version, migrate to manual superjson usage, or replace with native serialization
-  - This could affect all 30+ page files that use `getServerSideProps`
-
-### Turbopack Compatibility with GROWI
-- **Context**: Turbopack is the default bundler in Next.js 16; evaluating compatibility with GROWI's custom webpack config
-- **Sources Consulted**: [Turbopack API Reference](https://nextjs.org/docs/app/api-reference/turbopack)
-- **Findings**:
-  - Turbopack supports Pages Router and App Router
-  - Turbopack does NOT support `webpack()` configuration in `next.config.js`
-  - Turbopack does NOT support webpack plugins (e.g., `I18NextHMRPlugin`)
-  - Turbopack DOES support webpack loaders via `turbopack.rules` configuration
-  - Automatic import optimization eliminates need for `optimizePackageImports`
-  - Custom `pageExtensions`, `resolveAlias`, `resolveExtensions` are supported
-  - Sass is supported but `sassOptions.functions` is not
-- **GROWI-Specific Blockers**:
-  - `null-loader` rules for mongoose/dtrace-provider/mathjax-full → must be migrated to `turbopack.rules` or alternative exclusion mechanism
-  - `I18NextHMRPlugin` → no Turbopack equivalent; would need alternative HMR approach for i18n
-  - `source-map-loader` in dev mode → must be migrated to Turbopack loader config
-- **Implications**:
-  - Turbopack adoption requires migrating all custom webpack config
-  - The `--webpack` flag allows gradual migration (use Turbopack for dev, Webpack for build)
-  - Long-term Turbopack adoption is desirable but requires significant config migration
-
-### optimizePackageImports Effectiveness
-- **Context**: Evaluating whether expanding `optimizePackageImports` can reduce module count on current v14
-- **Sources Consulted**: [optimizePackageImports docs](https://nextjs.org/docs/pages/api-reference/config/next-config-js/optimizePackageImports), [Vercel blog](https://vercel.com/blog/how-we-optimized-package-imports-in-next-js)
-- **Findings**:
-  - Available since Next.js 13.5 (already usable on v14)
-  - Documented to reduce modules by up to 90% for barrel-heavy packages
-  - Benchmarks: `@material-ui/icons` 11,738 → 632 modules; `lucide-react` 1,583 → 333 modules
-  - Auto-optimized packages include: `lucide-react`, `date-fns`, `lodash-es`, `rxjs`, `@mui/*`, `recharts`, `react-use`, etc.
-  - Works by analyzing barrel files and remapping imports to specific module paths
-  - Handles nested barrel files and `export * from` patterns automatically
-- **Implications**:
-  - **Zero-risk, high-impact optimization** — can be applied immediately on v14
-  - Current GROWI config only covers 11 `@growi/*` packages
-  - Should be expanded to cover internal barrel-heavy directories and any third-party deps not in the auto-list
-
-### Bundle Analysis Tooling
-- **Context**: Need tooling to identify top module contributors and verify optimization impact
-- **Sources Consulted**: [Package Bundling Guide](https://nextjs.org/docs/pages/guides/package-bundling)
-- **Findings**:
-  - `@next/bundle-analyzer` already installed in GROWI; activated via `ANALYZE=true`
-  - `next experimental-analyze` (Turbopack-based) available in v16.1+ — more advanced with import chain tracing
-  - Bundle analyzer generates visual treemap reports for client and server bundles
-- **Implications**:
-  - Can run `ANALYZE=true pnpm run build` immediately to establish baseline
-  - Import chain tracing would help identify server module leakage paths
-  - v16.1 analyzer would be ideal but requires major version upgrade
-
-## Architecture Pattern Evaluation
-
-| Option | Description | Strengths | Risks / Limitations | Notes |
-|--------|-------------|-----------|---------------------|-------|
-| Phase 1: v14 Config Optimization | Expand optimizePackageImports, fix import violations, refactor barrel exports | Zero breaking changes, immediate impact, independently verifiable | Limited by Webpack tree-shaking; no `bundlePagesRouterDependencies` | Recommended first step |
-| Phase 2a: Next.js 15 Upgrade | Upgrade to v15 for `bundlePagesRouterDependencies` + `serverExternalPackages` | Unlocks Pages Router bundling control; stable features | next-superjson broken; React 19 migration | Requires superjson workaround |
-| Phase 2b: Turbopack Adoption (v16) | Upgrade to v16 with Turbopack default | Auto import optimization; 14x faster dev | webpack() config not supported; plugin migration | Longest-term option |
-
-## Design Decisions
-
-### Decision: Phased Approach — Config-First, Then Upgrade
-- **Context**: Need to reduce 10,066 modules with minimal risk while keeping upgrade path open
-- **Alternatives Considered**:
-  1. Direct Next.js 15 upgrade — high risk, next-superjson blocker
-  2. Config-only on v14 — safe but misses v15 bundling features
-  3. Hybrid phased approach — config first, upgrade informed by results
-- **Selected Approach**: Hybrid phased approach (Option C from gap analysis)
-- **Rationale**: Phase 1 provides immediate, low-risk wins. Phase 1 metrics inform whether Phase 2 upgrade is worth the migration cost. next-superjson blocker can be researched during Phase 1 without blocking progress.
-- **Trade-offs**: More total effort if upgrade is needed, but each phase independently delivers value
-- **Follow-up**: Measure module count after Phase 1; research next-superjson alternatives
-
-### Decision: Expand optimizePackageImports Before Refactoring Barrel Exports
-- **Context**: Both approaches reduce barrel export impact, but differ in effort and risk
-- **Alternatives Considered**:
-  1. Refactor all barrel exports to direct imports — high effort, many files affected
-  2. Expand `optimizePackageImports` to handle barrel files automatically — low effort, config-only
-  3. Both — maximum effect
-- **Selected Approach**: Expand `optimizePackageImports` first, measure impact, then refactor remaining barrels if needed
-- **Rationale**: `optimizePackageImports` achieves similar results to barrel refactoring with zero code changes. If the module count drops sufficiently, barrel refactoring may be unnecessary.
-- **Trade-offs**: `optimizePackageImports` may not catch all barrel patterns (e.g., side-effect-heavy modules)
-- **Follow-up**: Verify with bundle analysis which barrels are still problematic after config expansion
-
-### Decision: Fix Server Import Violations Over Expanding null-loader
-- **Context**: Server modules leaking into client bundle via direct imports
-- **Alternatives Considered**:
-  1. Expand null-loader rules for every server package — covers symptoms, not root cause
-  2. Fix import violations at source — eliminates the leakage path
-  3. Both — belt and suspenders
-- **Selected Approach**: Fix import violations at source as primary approach; expand null-loader as safety net for packages that might be transitively included
-- **Rationale**: Fixing imports is more maintainable than maintaining an ever-growing null-loader list. However, null-loader provides defense-in-depth for undiscovered leakage paths.
-- **Trade-offs**: Import fixes require more careful analysis; null-loader is simpler but masks problems
-- **Follow-up**: Use bundle analysis to confirm which server packages actually appear in client bundle
-
-## Risks & Mitigations
-- **Risk**: next-superjson incompatibility blocks Next.js 15 upgrade → **Mitigation**: Research alternatives during Phase 1; manual superjson serialization as fallback
-- **Risk**: Barrel export refactoring causes import breakage across codebase → **Mitigation**: Use `optimizePackageImports` first; refactor incrementally with tests
-- **Risk**: Module count reduction is insufficient from config-only changes → **Mitigation**: Bundle analysis will reveal if server module leakage is the primary cause, guiding whether upgrade is needed
-- **Risk**: I18NextHMRPlugin has no Turbopack equivalent → **Mitigation**: Use `--webpack` flag for dev until alternative is available; Turbopack adoption is Phase 2b
-
-## Phase 3: Next.js 15+ Feature Evaluation (Task 9.1)
-
-### Context
-
-Phase 2 achieved significant module reduction (initial: 2,704 → 895, -67%) through dynamic imports, null-loader expansion, and dependency replacement. Phase 3 evaluates whether upgrading to Next.js 15 provides additional meaningful optimization via `bundlePagesRouterDependencies` and `serverExternalPackages`.
-
-### Current State
-
-| Component | Version | Notes |
-|-----------|---------|-------|
-| Next.js | 14.2.35 | Pages Router, Webpack 5 |
-| React | 18.2.0 | |
-| next-superjson | 1.0.7 | SWC plugin wrapper for superjson serialization |
-| Node.js | 24.13.1 | Exceeds v15 minimum (18.18.0) |
-
-### Next.js 15 Features Relevant to Module Reduction
-
-#### 1. `bundlePagesRouterDependencies` (Stable)
-
-- **What it does**: Enables automatic server-side dependency bundling for Pages Router, matching App Router default behavior. All server-side dependencies are bundled into the server output instead of using native Node.js `require()` at runtime.
-- **Impact**: Improved cold start (pre-resolved deps), smaller deployment footprint via tree-shaking of server bundles. Does NOT directly reduce client-side initial module count (our primary KPI), but improves overall server-side build efficiency.
-- **Configuration**: `bundlePagesRouterDependencies: true` in `next.config.js`
-- **Risk**: Low — Next.js maintains an auto-exclude list for packages with native bindings (mongoose, mongodb, express, @aws-sdk/*, sharp are all auto-excluded)
-
-#### 2. `serverExternalPackages` (Stable)
-
-- **What it does**: Opt-out specific packages from server-side bundling when `bundlePagesRouterDependencies` is enabled. These packages use native `require()`.
-- **Auto-excluded packages relevant to GROWI**: `mongoose`, `mongodb`, `express`, `@aws-sdk/client-s3`, `@aws-sdk/s3-presigned-post`, `sharp`, `pino`, `ts-node`, `typescript`, `webpack`
-- **GROWI packages that may need manual addition**: `passport`, `ldapjs`, `nodemailer`, `multer`, `redis`, `connect-redis`, `@elastic/elasticsearch*`
-- **Configuration**: `serverExternalPackages: ['passport', ...]`
-
-#### 3. Turbopack (Stable for Dev in v15)
-
-- **Status**: Turbopack Dev is stable in Next.js 15. Default bundler in Next.js 16.
-- **Benefits**: Automatic import optimization (eliminates need for `optimizePackageImports`), 14x faster cold starts, 28x faster HMR
-- **GROWI blockers**: Does NOT support `webpack()` config. GROWI's null-loader rules, I18NextHMRPlugin, source-map-loader, and ChunkModuleStatsPlugin all require webpack config.
-- **Mitigation**: Can run with `--webpack` flag in dev to keep Webpack while upgrading Next.js. Turbopack adoption deferred to separate task.
-
-#### 4. Improved Tree-shaking and Module Resolution
-
-- **Better dead code elimination** in both Webpack and Turbopack modes
-- **SWC improvements** for barrel file optimization
-- **Not directly measurable** without upgrading — included as potential secondary benefit
-
-### `next-superjson` Compatibility Assessment
-
-#### Current Architecture
-
-GROWI uses `withSuperjson()` in `next.config.js` (line 184) which:
-1. Injects a custom webpack loader targeting `pages/` directory files
-2. The loader runs `@swc/core` with `next-superjson-plugin` to AST-transform each page
-3. **Auto-wraps** `getServerSideProps` with `withSuperJSONProps()` (serializes props via superjson)
-4. **Auto-wraps** page default export with `withSuperJSONPage()` (deserializes props on client)
-
-Custom serializers registered in `_app.page.tsx`:
-- `registerTransformerForObjectId()` — handles MongoDB ObjectId serialization (no mongoose dependency)
-- `registerPageToShowRevisionWithMeta()` — handles page revision data (called in `[[...path]]` page)
-
-#### Compatibility Options
-
-| Option | Approach | Risk | Effort |
-|--------|----------|------|--------|
-| A. Upgrade `next-superjson` to 1.0.8 | Claims v15 support via frozen `@swc/core@1.4.17` | Medium — fragile SWC binary pinning; underlying plugin unmaintained | Minimal (version bump) |
-| B. Use `superjson-next@0.7.x` fork | Community SWC plugin with native v15 support | Medium — third-party fork, SWC plugins inherently fragile | Low (config change) |
-| C. Manual superjson (per-page wrapping) | Remove plugin; use helper functions + wrap each page's `getServerSideProps` | Low — no SWC plugin dependency | Medium (create helpers, wrap 38 pages) |
-| **D. Custom webpack loader (Recommended)** | **Remove plugin; use a simple regex-based webpack loader to auto-wrap `getServerSideProps`** | **Low — no SWC/Babel dependency, webpack loader API is stable** | **Low (create loader + config, no per-page changes)** |
-
-#### Detailed Assessment of Option A: `next-superjson` v1.0.8 / v2.0.0
-
-Both v1.0.8 and v2.0.0 were published on the same day (Oct 18, 2025). They share identical code — the only difference is the peer dependency declaration (`next >= 10` vs `next >= 16`).
-
-**How v1.0.8 achieves "Next.js 15 support"**:
-1. Does NOT use Next.js's built-in SWC plugin system
-2. Registers a custom webpack/turbopack loader targeting `pages/` directory files
-3. This loader uses a **bundled `@swc/core` pinned to v1.4.17 (March 2024)** to run a separate SWC compilation
-4. The pinned SWC loads the `next-superjson-plugin` v0.6.3 WASM binary
-
-**Risks**:
-- **Double SWC compilation**: Page files are compiled by both Next.js's SWC and the plugin's frozen SWC — potential for conflicts and performance overhead
-- **Pinned binary fragility**: `@swc/core@1.4.17` is from early 2024; SWC plugin ABI is notoriously unstable across versions
-- **Unmaintained upstream**: The `next-superjson-plugin` v0.6.3 WASM binary comes from `blitz-js/next-superjson-plugin`, which has unmerged PRs and open issues for v15 compatibility
-- **Low adoption**: Published Oct 2025, minimal community usage
-
-**Conclusion**: The "support" is a fragile workaround, not genuine compatibility. Rejected.
-
-#### Recommended: Option D — Custom Webpack Loader
-
-**Why**: Achieves the same zero-page-change DX as the original `next-superjson` plugin, but without any SWC/Babel dependency. The loader is a simple regex-based source transform (~15 lines) that auto-wraps `getServerSideProps` exports with `withSuperJSONProps()`. Webpack's loader API is stable across versions, making this future-proof.
-
-**How it works**:
-1. A webpack loader targets `.page.{ts,tsx}` files
-2. If the file exports `getServerSideProps`, the loader:
-   - Prepends `import { withSuperJSONProps } from '~/pages/utils/superjson-ssr'`
-   - Renames `export const getServerSideProps` → `const __getServerSideProps__`
-   - Appends `export const getServerSideProps = __withSuperJSONProps__(__getServerSideProps__)`
-3. Deserialization is centralized in `_app.page.tsx` (same as Option C)
-
-**Migration plan**:
-1. Create `withSuperJSONProps()` and `deserializeSuperJSONProps()` helpers in `src/pages/utils/superjson-ssr.ts`
-2. Create `src/utils/superjson-ssr-loader.js` — simple regex-based webpack loader
-3. Add loader rule in `next.config.js` webpack config (targets `.page.{ts,tsx}` files)
-4. Add centralized deserialization in `_app.page.tsx`
-5. Remove `next-superjson` dependency and `withSuperjson()` from `next.config.js`
-6. Keep `superjson` as direct dependency; keep all `registerCustom` calls unchanged
-
-**Advantages over Option C**:
-- Zero per-page file changes (38 fewer files modified)
-- Diff is ~20 lines total instead of ~660 lines
-- Closer to the original `next-superjson` DX (config-only, transparent to page authors)
-- New pages automatically get superjson serialization without manual wrapping
-
-**Scope**: 3 files changed (loader, next.config.js, _app.page.tsx) + 1 new file (superjson-ssr.ts with helpers)
-
-### Breaking Changes Affecting GROWI (Pages Router)
-
-| Change | Impact | Action Required |
-|--------|--------|-----------------|
-| Node.js ≥ 18.18.0 required | None — GROWI uses Node 24.x | No action |
-| `@next/font` → `next/font` | None — GROWI does not use `@next/font` | No action |
-| `swcMinify` enabled by default | Low — already effective | No action |
-| `next/dynamic` `suspense` prop removed | Verify — GROWI uses `next/dynamic` extensively | Check all `dynamic()` calls for `suspense` prop |
-| `eslint-plugin-react-hooks` v5.0.0 | Low — may trigger new lint warnings | Run lint after upgrade |
-| Config renames (`experimental.bundlePagesExternals` → `bundlePagesRouterDependencies`) | None — GROWI doesn't use the experimental names | No action |
-| `next/image` `Content-Disposition` changed | None — GROWI uses standard `next/image` | No action |
-| Async Request APIs (cookies, headers) | None — App Router only | No action |
-| React 19 peer dependency | None — Pages Router supports React 18 backward compat | Stay on React 18 |
-
-### Decision: Proceed with Next.js 15 Upgrade
-
-**Rationale**:
-1. **`bundlePagesRouterDependencies` + `serverExternalPackages`** provide proper server-side dependency bundling, completing the optimization work started in Phase 2
-2. **Breaking changes for Pages Router are minimal** — no async API changes, no React 19 requirement
-3. **`next-superjson` blocker is resolved** via custom webpack loader (Option D) — zero per-page changes, same transparent DX as original plugin
-4. **No Turbopack migration needed** — continue using Webpack with `--webpack` flag in dev
-5. **Phase 2 results (initial: 895 modules)** are already strong; v15 features provide server-side improvements and lay groundwork for future Turbopack adoption
-
-**Expected benefits**:
-- Server-side bundle optimization via `bundlePagesRouterDependencies`
-- Proper `serverExternalPackages` support (replaces null-loader workaround for some packages)
-- Modern Next.js foundation for future improvements (Turbopack, App Router migration path)
-- Elimination of fragile SWC plugin dependency (`next-superjson`) — replaced by simple webpack loader with no external dependencies
-
-**Risks and mitigations**:
-- `I18NextHMRPlugin` — Keep using Webpack bundler in dev (`--webpack` flag if needed)
-- Test regressions — Full test suite + typecheck + lint + build verification
-- Superjson serialization — Test all page routes for correct data serialization/deserialization
-
-## References
-- [Next.js v15 Upgrade Guide](https://nextjs.org/docs/app/guides/upgrading/version-15) — Breaking changes inventory
-- [Turbopack API Reference](https://nextjs.org/docs/app/api-reference/turbopack) — Supported features and known gaps
-- [optimizePackageImports (Pages Router)](https://nextjs.org/docs/pages/api-reference/config/next-config-js/optimizePackageImports) — Config documentation
-- [Package Bundling Guide (Pages Router)](https://nextjs.org/docs/pages/guides/package-bundling) — bundlePagesRouterDependencies, serverExternalPackages
-- [How we optimized package imports in Next.js](https://vercel.com/blog/how-we-optimized-package-imports-in-next-js) — Benchmarks and approach
-- [next-superjson GitHub](https://github.com/remorses/next-superjson) — Compatibility status
-- [next-superjson-plugin GitHub](https://github.com/blitz-js/next-superjson-plugin) — SWC plugin (unmaintained)
-- [superjson-next fork](https://github.com/serg-and/superjson-next) — Community fork with v15 support
-- [Next.js 15.5 Blog Post](https://nextjs.org/blog/next-15-5) — Latest features
-- [server-external-packages.jsonc](https://github.com/vercel/next.js/blob/canary/packages/next/src/lib/server-external-packages.jsonc) — Auto-excluded server packages

+ 0 - 22
.kiro/specs/reduce-modules-loaded/spec.json

@@ -1,22 +0,0 @@
-{
-  "feature_name": "reduce-modules-loaded",
-  "created_at": "2026-02-18T00:00:00.000Z",
-  "updated_at": "2026-02-24T05:30:00.000Z",
-  "language": "en",
-  "phase": "ready-for-implementation",
-  "approvals": {
-    "requirements": {
-      "generated": true,
-      "approved": true
-    },
-    "design": {
-      "generated": true,
-      "approved": true
-    },
-    "tasks": {
-      "generated": true,
-      "approved": true
-    }
-  },
-  "ready_for_implementation": true
-}

+ 0 - 277
.kiro/specs/reduce-modules-loaded/tasks.md

@@ -1,277 +0,0 @@
-# Implementation Plan
-
-## Progress Tracking Convention
-
-Analysis tasks (1.2, 3.1, 3.2, 4.1, 5.1, 5.2) may discover a large number of target files. To enable **resumability** and **progress tracking** across interrupted sessions, use the following approach:
-
-### Analysis Ledger File
-
-Create `.kiro/specs/reduce-modules-loaded/analysis-ledger.md` during task 1.2 and maintain it throughout Phase 1. This file serves as the single source of truth for discovered targets and their fix status.
-
-**Structure**:
-```markdown
-# Analysis Ledger
-
-## Measurements
-| Step | Task | Modules | Time | Date |
-|------|------|---------|------|------|
-| Baseline | 1.1 | 10,066 | 51.5s | YYYY-MM-DD |
-| After optimizePackageImports | 2.2 | N | Xs | YYYY-MM-DD |
-| ... | ... | ... | ... | ... |
-
-## Import Violations (Task 3)
-| # | File | Violation | Fix Strategy | Status |
-|---|------|-----------|--------------|--------|
-| 1 | src/client/.../ActivityListItem.tsx | imports ~/server/util/locale-utils | Extract getLocale to client util | pending |
-| 2 | src/client/.../PageBulkExportJobModelNotification.tsx | imports serializer with mongoose | Split parseSnapshot to client module | pending |
-| ... | | | | |
-
-## Server Packages in Client Bundle (Task 4)
-| # | Package | Confirmed in Client Bundle | null-loader Added | Status |
-|---|---------|---------------------------|-------------------|--------|
-| 1 | mongoose | Yes (existing rule) | Yes | done |
-| 2 | @elastic/elasticsearch | TBD | No | pending |
-| ... | | | | |
-
-## Barrel Exports to Refactor (Task 5)
-| # | File | Issue | Still Impactful After optimizePackageImports? | Status |
-|---|------|-------|-----------------------------------------------|--------|
-| 1 | src/utils/axios/index.ts | export * from 'axios' | N/A (always fix) | pending |
-| 2 | src/states/ui/editor/index.ts | 7 wildcard exports | TBD | pending |
-| ... | | | | |
-```
-
-**Rules**:
-- **Create** the ledger during task 1.2 with initial findings
-- **Append** new discoveries as each analysis task runs (tasks 3, 4, 5)
-- **Update Status** to `done` as each individual fix is applied
-- **Read** the ledger at the start of every task to understand current state
-- When resuming after an interruption, the ledger tells you exactly where to pick up
-
-## Phase 1: v14 Optimizations
-
-- [x] 1. Establish baseline dev compilation measurement
-- [x] 1.1 Record baseline module count and compilation time
-  - Baseline: 10,066 modules / 51.5s (reported)
-  - _Requirements: 2.1, 6.1_
-
-- [x] 1.2 (P) Run supplementary bundle analysis and create analysis ledger
-  - Created `analysis-ledger.md` with comprehensive findings
-  - Scanned all client/server import violations, barrel exports, server package candidates
-  - _Requirements: 1.4, 2.1, 2.2, 2.3_
-
-- [x] 2. Expand `optimizePackageImports` configuration — **REJECTED (reverted)**
-- [x] 2.1 Identify barrel-heavy packages to add
-  - Identified: reactstrap (199-line barrel, 124 import sites), react-hook-form (2,602-line barrel, 31 sites), react-markdown (321-line barrel, 6 sites)
-  - _Requirements: 1.1, 1.2, 1.3_
-
-- [x] 2.2 Add candidate packages to the config and measure impact — **REVERTED**
-  - Added reactstrap, react-hook-form, react-markdown to `optimizePackageImports` in `next.config.js`
-  - **Actual measurement: +213 modules (10,066 → 10,279), no compilation time improvement**
-  - `optimizePackageImports` resolves individual module files instead of barrel, resulting in MORE module entries in webpack's dev compilation graph
-  - **Decision: Reverted — config change not included in commit**
-  - _Requirements: 4.3, 4.4, 6.1_
-
-- [x] 3. Fix client-to-server import violations
-- [x] 3.1 Scan for all import violations and update the ledger
-  - Found 2 violations: ActivityListItem.tsx → ~/server/util/locale-utils, PageBulkExportJobModelNotification.tsx → serializer with mongoose
-  - _Requirements: 3.1, 3.3_
-
-- [x] 3.2 (P) Fix all identified import violations
-  - Violation 1: Extracted `getLocale` to `src/utils/locale-utils.ts` (client-safe); updated ActivityListItem.tsx and server module
-  - Violation 2: Created `page-bulk-export-job-client.ts` with `parseSnapshot` + `IPageBulkExportJobSnapshot`; updated client component import
-  - Tests: 18 new tests (15 for locale-utils, 3 for page-bulk-export-job-client) — all pass
-  - _Requirements: 3.1, 3.2, 3.3_
-
-- [x] 3.3 Measure impact of import violation fixes
-  - **Actual measurement: 10,068 modules (vs 10,066 baseline) — +2 modules, no compilation time change (~31s)**
-  - Import violation fixes are architecturally correct (server/client boundary) but do not reduce compilation time
-  - _Requirements: 6.1_
-
-- [x] 4. Expand null-loader rules for server-only packages in client bundle
-- [x] 4.1 Confirm which server packages appear in the client bundle
-  - Comprehensive analysis of all 16 candidate server packages
-  - **Result: No additional server packages are reachable from client code** — all are properly isolated to server-only import paths
-  - openai uses `import type` only in client-reachable interfaces (erased at compile time)
-  - _Requirements: 3.1, 3.2_
-
-- [x] 4.2 Add null-loader rules and measure impact
-  - **No additional null-loader rules needed** — existing rules (mongoose, dtrace-provider, mathjax-full) are sufficient
-  - _Requirements: 3.1, 3.2, 6.1_
-
-- [x] 5. Refactor high-impact barrel exports
-- [x] 5.1 Fix the axios barrel re-export
-  - Removed `export * from 'axios'` — confirmed unused by all 7 consumers (all use default import only)
-  - All 15 existing axios tests pass
-  - _Requirements: 4.1, 4.2_
-
-- [x] 5.2 Evaluate and refactor remaining barrel exports
-  - Evaluated 5 internal barrel files (states/ui/editor, features/page-tree, states/page, etc.)
-  - **Result: No refactoring needed** — internal barrels re-export from small focused files within same domain; `optimizePackageImports` only applies to node_modules packages
-  - _Requirements: 4.1, 4.2_
-
-- [x] 5.3 Measure impact of barrel export refactoring
-  - **Actual measurement: Removing `export * from 'axios'` had no measurable impact on modules or compilation time**
-  - _Requirements: 6.1_
-
-- [x] 6. Verify lazy-loaded components are excluded from initial compilation
-  - Verified all 30 LazyLoaded components follow correct pattern
-  - All index.ts files re-export only from dynamic.tsx
-  - All dynamic.tsx files use useLazyLoader with dynamic import()
-  - No static imports of actual components found
-  - _Requirements: 7.1, 7.2, 7.3_
-
-- [x] 7. Phase 1 final measurement and regression verification
-- [x] 7.1 Record final dev compilation metrics
-  - **Actual measurement (committed changes only, without optimizePackageImports):**
-  - Baseline: 10,066 modules / ~31s
-  - After committed Phase 1 changes: 10,068 modules / ~31s
-  - **Result: No meaningful compilation time reduction from Phase 1 code changes**
-  - Phase 1 changes are valuable as code quality improvements (server/client boundary, unused re-exports) but do not achieve the compilation time reduction goal
-  - _Requirements: 6.1, 6.2, 6.3_
-
-- [x] 7.2 Run full regression test suite
-  - Type checking: Zero errors (tsgo --noEmit)
-  - Biome lint: 1,776 files checked, no errors
-  - Tests: 107 test files pass (1,144 tests); 8 integration test timeouts are pre-existing MongoDB environment issue
-  - Production build: Succeeds
-  - _Requirements: 6.2, 6.3_
-
-## Phase 2: Iterative Module Reduction (Dynamic Import & Import Optimization)
-
-### KPI
-
-- **Primary**: `[ChunkModuleStats] initial` — modules in eager (initial) chunks
-- **Baseline**: initial: 2,704 (before Phase 2 changes)
-- Measured via `bin/measure-chunk-stats.sh` (cleans `.next`, starts `next dev`, triggers compilation, outputs ChunkModuleStats)
-
-### Reduction Loop
-
-The following loop repeats until the user declares completion:
-
-1. **Measure** — Run `bin/measure-chunk-stats.sh`, record `initial` / `async-only` / `total` in `analysis-ledger.md`
-2. **Analyze & Propose** — Analyze the initial chunk module graph, identify the top contributors, and propose one or more reduction approaches (e.g., `next/dynamic`, import refactoring, dependency replacement). Alternatively, if further reduction is impractical, propose ending the loop.
-3. **User Decision** — The user approves the proposed approach, adjusts it, or declares the loop complete.
-4. **Implement & Verify** — Apply the approved changes, then run `turbo run lint:typecheck --filter @growi/app && turbo run lint:biome --filter @growi/app`. Fix any errors before returning to step 1.
-
-### Task Log
-
-- [x] 8.1 Phase 1 sufficiency assessment
-  - **Assessment: Phase 1 is insufficient for compilation time reduction.** Changes are code quality improvements only.
-  - Full assessment documented in `analysis-ledger.md`
-  - _Requirements: 5.1_
-
-- [x] 8.2 Establish ChunkModuleStats KPI and measurement tooling
-  - Created `ChunkModuleStatsPlugin` in `src/utils/next.config.utils.js`
-  - Created `bin/measure-chunk-stats.sh` for one-command measurement
-  - Baseline recorded: initial: 2,704 / async-only: 4,146 / total: 6,850
-  - _Requirements: 2.1, 6.1_
-
-- [x] 8.3 Loop iteration 1: MermaidViewer dynamic import + date-fns subpath imports
-  - MermaidViewer → `next/dynamic({ ssr: false })` in client renderer
-  - date-fns barrel → subpath imports (12 files)
-  - Result: initial: 2,128 (-576, -21.3%) / async-only: 4,717 / total: 6,845
-  - _Requirements: 7.2, 4.1, 6.1_
-
-- [x] 8.4 Loop iteration 2: date-fns locale barrel → individual subpath imports
-  - Converted `locale-utils.ts` import from `date-fns/locale` barrel (96 locales × 6 modules = ~576 modules) to individual subpath imports (`date-fns/locale/en-US`, `/fr`, `/ja`, `/ko`, `/zh-CN`)
-  - Updated `locale-utils.spec.ts` import paths to match
-  - Enhanced `ChunkModuleStatsPlugin` with `DUMP_INITIAL_MODULES=1` diagnostic mode for per-package breakdown
-  - Result: initial: 1,630 (-498, -23.4%) / async-only: 4,717 / total: 6,347 / compiled: 9,062
-  - date-fns: 560 → 62 modules in initial chunks
-  - _Requirements: 4.1, 6.1_
-
-- [x] 8.5 Loop iteration 3: null-loader expansion for server-only package leaks
-  - Added null-loader rules for `i18next-fs-backend` (server-only filesystem translation backend leaking via next-i18next), `bunyan` (server-only logging; client uses browser-bunyan via universal-bunyan), and `bunyan-format` (server-only log formatter)
-  - Null-loading bunyan eliminated its entire transitive dependency tree: mv, ncp, mkdirp, rimraf, glob, source-map, source-map-support, and other Node.js utilities
-  - Result: initial: 1,572 (-58, -3.6%) / async-only: 4,720 / total: 6,292 / compiled: 9,007
-  - _Requirements: 3.1, 3.2, 6.1_
-
-- [x] 8.6 Loop iteration 4: validator → isMongoId regex replacement in LinkEditModal
-  - Replaced `import validator from 'validator'` with lightweight `isMongoId()` regex utility (`/^[0-9a-f]{24}$/i`)
-  - Created `src/client/util/mongo-id.ts` with `isMongoId()` and `mongo-id.spec.ts` with 8 unit tests (TDD)
-  - Eliminated all 113 `validator` modules from async-only chunks (single usage: `validator.isMongoId()` in LinkEditModal.tsx)
-  - Result: initial: 1,572 (unchanged) / async-only: 4,608 (-112, -2.4%) / total: 6,180 (-112) / compiled: 8,895 (-112)
-  - _Requirements: 4.1, 6.1_
-
-- [x] 8.7 Loop iteration 5: react-hotkeys → tinykeys migration
-  - Replaced `react-hotkeys` (91 async modules) with `tinykeys` (~400 byte, 1 module)
-  - Rewrote `HotkeysManager.tsx` to use tinykeys directly with inline key bindings
-  - Deleted `HotkeysDetector.jsx` (unused), `HotkeyStroke.js` (unused model)
-  - Removed `getHotkeyStrokes()` static methods from all 6 subscriber components
-  - Removed `react-hotkeys` dependency, added `tinykeys` dependency
-  - Added `HotkeysManager.spec.tsx` with 6 tests (single keys, modifier keys, editable target suppression)
-  - Refactored all 6 subscriber components to align with ideal patterns:
-    - Converted 4 JSX files to TypeScript (CreatePage, FocusToGlobalSearch, ShowStaffCredit, SwitchToMirrorMode)
-    - Fixed `onDeleteRender(this)` bug in 3 files (`this` is undefined in functional components)
-    - Replaced PropTypes with TypeScript `Props` type in all subscribers
-    - Removed unnecessary `React.memo` wrapper from CreatePage
-    - Unified return values: `return null` for logic-only components
-    - Converted all 6 subscribers from default exports to named exports
-  - Result: initial: 1,573 (+1) / async-only: 4,516 (-92) / total: 6,089 (-91) / compiled: 8,802 (-93)
-  - _Requirements: 4.1, 6.1_
-
-- [x] 8.8 Loop iteration 6: markdown rendering pipeline → next/dynamic({ ssr: true })
-  - Created `PageContentRenderer` wrapper component encapsulating `RevisionRenderer` + `generateSSRViewOptions`
-  - Converted `PageContentRenderer` to `next/dynamic({ ssr: true })` in both `PageView.tsx` and `ShareLinkPageView.tsx`
-  - Moves entire markdown pipeline (react-markdown, katex, remark-gfm, rehype-katex, mdast-util-to-markdown, etc.) to async chunks while preserving SSR rendering
-  - Added `PageContentRenderer.spec.tsx` with 3 tests (null markdown, generated options, explicit options)
-  - Result: initial: 1,073 (-500, -31.8%) / async-only: 5,016 (+500) / total: 6,089 (unchanged) / compiled: 8,803 (+1)
-  - _Requirements: 7.2, 6.1_
-
-- [x] 8.9 Loop iteration 7: core-js null-load + ChunkModuleStatsPlugin analysis fix
-  - Added null-loader rule for `core-js` on client side — polyfills baked into next-i18next/react-stickynode dist files; all APIs natively supported by target browsers (Chrome 64+, Safari 12+)
-  - Null-loading eliminates 179 core-js transitive dependency modules; 37 entry-point modules remain as empty stubs
-  - Fixed `ChunkModuleStatsPlugin` to strip webpack loader prefixes (e.g., `source-map-loader!/path`) before package attribution — corrects 82 previously misattributed modules
-  - Result: initial: 894 (-179, -16.7%) / async-only: 5,011 (-5) / total: 5,905 (-184) / compiled: 8,619 (-184)
-  - _Requirements: 3.1, 3.2, 6.1_
-
-- [x] 8.10 Loop iteration 8: react-syntax-highlighter deep ESM import + v16 upgrade
-  - Changed barrel import `import { PrismAsyncLight } from 'react-syntax-highlighter'` to deep ESM import `import PrismAsyncLight from 'react-syntax-highlighter/dist/esm/prism-async-light'` in all 4 usage files
-  - Changed style import from `dist/cjs/styles/prism` barrel to `dist/esm/styles/prism/one-dark` direct import
-  - Upgraded react-syntax-highlighter from 15.5.0 to 16.1.0 (refractor v3→v5 security fix, webpack 5 improvements, API unchanged)
-  - Deep import bypasses barrel that re-exports all engines (highlight.js, Prism, etc.); only Prism/refractor engine is bundled
-  - Remaining highlight.js modules (~149) still present via other paths (diff2html, lowlight)
-  - Result: initial: 895 (+1) / async-only: 4,775 (-236, -4.7%) / total: 5,670 (-235)
-  - _Requirements: 4.1, 6.1_
-
-- [ ] 8.N Loop iteration N: (next iteration — measure, analyze, propose, implement)
-
-## Phase 3: Next.js Version Upgrade Evaluation (Deferred)
-
-- [x] 9.1 Document Next.js 15+ feature evaluation
-  - Documented all Next.js 15+ features relevant to module reduction: `bundlePagesRouterDependencies`, `serverExternalPackages`, Turbopack (stable dev), improved tree-shaking
-  - Assessed `next-superjson` blocker: 4 options evaluated (A: v1.0.8 upgrade, B: superjson-next fork, C: manual per-page wrapping, D: custom webpack loader)
-  - **Option A (`next-superjson` v1.0.8) rejected** — achieves "v15 support" via fragile `@swc/core@1.4.17` pinning with double SWC compilation; depends on unmaintained WASM binary
-  - **Option D (custom webpack loader) selected** — zero-dependency regex-based source transform; same transparent DX as original plugin with no per-page changes
-  - Breaking changes for Pages Router are minimal (no async API changes, React 18 backward compat confirmed)
-  - **Decision: Proceed with Next.js 15 upgrade** — benefits outweigh minimal risk
-  - Full evaluation documented in `research.md` under "Phase 3: Next.js 15+ Feature Evaluation"
-  - _Requirements: 1.1, 1.2, 1.3, 5.1, 5.4_
-
-- [ ] 9.2 Execute Next.js 15 upgrade
-  - Migrated from `next-superjson` SWC plugin to custom webpack loader approach:
-    - Created `withSuperJSONProps()` and `deserializeSuperJSONProps()` in `src/pages/utils/superjson-ssr.ts` (10 tests)
-    - Created `src/utils/superjson-ssr-loader.js` — regex-based webpack loader that auto-wraps `getServerSideProps` exports
-    - Added loader rule in `next.config.js` targeting `.page.{ts,tsx}` files
-    - Added centralized deserialization in `_app.page.tsx`
-    - Removed `next-superjson` dependency and `withSuperjson()` from `next.config.js`
-    - **Zero per-page file changes** — loader transparently handles all 38 pages
-  - Upgraded Next.js 14.2.35 → 15.5.12, `@next/bundle-analyzer` 14.1.3 → 15.5.12
-  - Updated peer deps in `@growi/presentation`, `@growi/remark-lsx`, `@growi/ui` to `^14 || ^15`
-  - _Requirements: 5.2, 5.3_
-
-- [x] 9.3 Enable v15-specific module optimization features
-  - Added `bundlePagesRouterDependencies: true` to `next.config.js` — bundles server-side dependencies for Pages Router, matching App Router behavior
-  - Added `serverExternalPackages: ['handsontable']` — legacy `handsontable@6.2.2` requires unavailable `@babel/polyfill`; client-only via dynamic import, kept external on server
-  - Auto-excluded packages (mongoose, mongodb, express, sharp, and 68 others) handled by Next.js built-in list
-  - `serverExternalPackages` replaces `experimental.serverComponentsExternalPackages` (now stable in v15)
-  - Production build passes with new configuration
-  - _Requirements: 3.4, 5.2_
-
-- [x] 9.4 Run full regression test suite after upgrade
-  - Type checking: Zero errors (tsgo --noEmit)
-  - Biome lint: 1,791 files checked, no errors
-  - Tests: 127 test files, 1,375 tests — all passed
-  - Production build: Passes with `bundlePagesRouterDependencies: true` + `serverExternalPackages`
-  - _Requirements: 5.3, 6.2, 6.3_