Yuki Takei 21 часов назад
Родитель
Сommit
54c168cd65

+ 0 - 99
.kiro/specs/suggest-path/tasks.md

@@ -4,100 +4,19 @@
 
 
 - [x] 1. Phase 1 MVP — Shared types, memo path suggestion, and endpoint registration
 - [x] 1. Phase 1 MVP — Shared types, memo path suggestion, and endpoint registration
 - [x] 1.1 Define suggestion types and implement memo path generation
 - [x] 1.1 Define suggestion types and implement memo path generation
-  - Define the suggestion response types used across both phases: suggestion type discriminator, individual suggestion structure with type/path/label/description/grant fields, and the response wrapper
-  - Implement memo path generation: when user pages are enabled (default), generate path under the user's home directory with owner-only grant; when user pages are disabled, generate path under an alternative namespace with hardcoded owner-only grant (actual parent grant resolution deferred to Phase 2 task 2)
-  - Enforce directory path format with trailing slash for all generated paths
-  - Generate fixed descriptive text for memo suggestions
-  - Include unit tests covering both user-pages-enabled and user-pages-disabled paths, verifying correct path format, grant value, and description
-  - _Requirements: 1.2, 1.3, 2.1, 2.2, 2.3, 2.4, 2.5, 6.1, 6.2_
-
 - [x] 1.2 Register route endpoint with authentication and validation
 - [x] 1.2 Register route endpoint with authentication and validation
-  - Create the route under a new namespace separate from the page API, following the existing handler factory pattern
-  - Apply the standard middleware chain: access token parsing, strict login requirement, AI service gating, request body validation
-  - Implement the handler to invoke memo suggestion generation for the authenticated user and return the suggestions array using the standard API response format
-  - Return appropriate error responses for authentication failures, validation failures, and AI-disabled states without exposing internal system details
-  - Register the new namespace route in the central API router
-  - _Requirements: 1.1, 1.4, 8.1, 8.2, 8.3, 9.1, 9.2_
-
 - [x] 1.3 Phase 1 integration verification
 - [x] 1.3 Phase 1 integration verification
-  - Verify the complete request-response cycle for the memo suggestion endpoint with valid authentication
-  - Verify authentication enforcement: unauthenticated requests receive appropriate error responses
-  - Verify input validation: requests with missing or empty body field receive validation errors
-  - Verify AI service gating: requests when AI is disabled receive appropriate error responses
-  - Verify response structure: correct fields, trailing slash on path, correct grant value
-  - _Requirements: 1.1, 1.2, 1.3, 1.4, 2.1, 8.1, 8.2, 9.1, 9.2_
 
 
 ## Phase 2 — Revised
 ## Phase 2 — Revised
 
 
 - [x] 2. (P) Enhance grant resolver for ancestor path traversal
 - [x] 2. (P) Enhance grant resolver for ancestor path traversal
-  - Enhance the existing grant resolution to support paths that may not yet exist in GROWI, as required by the sibling pattern where new directory names are generated
-  - When the direct parent page exists, return its grant value as the upper bound for child page permissions
-  - When the direct parent page is not found, traverse upward through ancestor paths to find the nearest existing page's grant
-  - When no ancestor page is found at any level, return owner-only grant as a safe default
-  - Include unit tests for: direct parent found, ancestor found at various depths, no ancestor found (safe default), root-level paths, paths with trailing slashes
-  - _Requirements: 7.1, 7.2_
-
 - [x] 3. (P) Content analysis via GROWI AI (1st AI call)
 - [x] 3. (P) Content analysis via GROWI AI (1st AI call)
-  - Implement content analysis that delegates to GROWI AI for a single AI call performing both keyword extraction and flow/stock information type classification
-  - Extract 1-5 keywords from the content, prioritizing proper nouns and technical terms over generic words
-  - Classify the content as either flow information (time-bound: meeting notes, diaries, reports) or stock information (reference: documentation, knowledge base articles)
-  - Reference the existing flow/stock classification guidance as a prompt reference, without treating it as the sole classification criterion
-  - On analysis failure or inability to produce usable keywords, throw an error so the caller can handle fallback logic
-  - Include unit tests for: successful keyword extraction with quality verification, correct flow/stock classification for representative content samples, edge cases (very short content, ambiguous content), and failure propagation
-  - _Requirements: 5.1, 5.2, 5.4_
-
 - [x] 4. (P) Search candidate retrieval with score threshold filtering
 - [x] 4. (P) Search candidate retrieval with score threshold filtering
-  - Implement search candidate retrieval that searches for related pages using extracted keywords via the existing search service
-  - Use extracted keywords (not raw content body) for search operations
-  - Filter search results using an Elasticsearch score threshold to retain only sufficiently relevant candidates
-  - Return an array of candidates with page path, snippet, and score for downstream AI evaluation
-  - Return an empty array if no results pass the threshold, allowing the caller to omit search-based suggestions
-  - The score threshold value is configurable and will be tuned with real data during implementation
-  - Include unit tests for: multi-result retrieval, threshold filtering (candidates above/below/at threshold), empty result handling, and correct candidate structure
-  - _Requirements: 3.1, 3.2, 3.5, 5.3_
-
 - [x] 5. (P) AI-based candidate evaluation and path proposal (2nd AI call)
 - [x] 5. (P) AI-based candidate evaluation and path proposal (2nd AI call)
-  - Implement candidate evaluation that delegates to GROWI AI for a single AI call evaluating search candidates for content-destination fit
-  - Evaluate each candidate's suitability by passing the content body, the content analysis results (keywords and informationType from the 1st AI call), and each candidate's path and search snippet
-  - For each suitable candidate, propose a save location using one of three structural patterns relative to the matching page: (a) parent directory, (b) subdirectory under the matching page, (c) sibling directory alongside the matching page
-  - When the sibling pattern is selected, generate an appropriate new directory name based on the content being saved; the generated path must be at the same hierarchy level as the matching search candidate page
-  - Generate a description for each suggestion explaining why the location is suitable, considering content relevance and flow/stock alignment
-  - Rank suggestions by content-destination fit, using flow/stock information type alignment as a ranking factor rather than a hard filter
-  - Pass candidate paths and ES snippets to the AI context, not full page bodies, to manage AI context budget
-  - On evaluation failure, throw an error so the caller can handle fallback logic
-  - Include unit tests for: path pattern selection across all three patterns, sibling path generation at correct hierarchy level, AI-generated description quality, ranking order, flow/stock alignment consideration, and failure propagation
-  - _Requirements: 3.3, 6.3, 10.1, 10.2, 10.3, 10.4, 11.1, 11.2, 11.3, 12.1, 12.2, 12.3, 12.4_
-
 - [x] 6. (P) Category-based path suggestion (under review — prior implementation retained)
 - [x] 6. (P) Category-based path suggestion (under review — prior implementation retained)
-  - This component has an existing implementation from the prior Phase 2 design; it is retained as-is pending reviewer discussion on whether to keep, merge, or remove
-  - Search for matching pages scoped to top-level directories using extracted keywords
-  - Extract the top-level path segment from the most relevant result as the suggested category directory
-  - Generate a description from the top-level segment name using mechanical text, not AI
-  - Resolve the parent page's grant value via grant resolution
-  - Return null when no matching top-level pages are found, so this suggestion type is omitted from the response
-  - Include unit tests for: top-level segment extraction, description generation, grant resolution, and empty result handling
-  - _Requirements: 4.1, 4.2, 4.3, 4.4_
-
 - [x] 7. Phase 2 revised orchestration and integration
 - [x] 7. Phase 2 revised orchestration and integration
 - [x] 7.1 Rewrite orchestration for revised Phase 2 pipeline
 - [x] 7.1 Rewrite orchestration for revised Phase 2 pipeline
-  - Rewrite the orchestration function to implement the revised Phase 2 pipeline: always generate memo suggestion first as guaranteed fallback, then invoke content analysis (1st AI call), pass keywords to search candidate retrieval, pass candidates to candidate evaluation (2nd AI call), and run category generation in parallel with the search-evaluate pipeline
-  - After candidate evaluation returns, resolve grant for each proposed path via grant resolver
-  - Map the informationType from content analysis onto each search-type suggestion in the final response, and add informationType as an optional field on the suggestion type
-  - Ensure the response includes both structured metadata (informationType, type, grant) and natural language context (description) for client LLM independence
-  - Ensure all reasoning-intensive operations (keyword extraction, flow/stock classification, candidate evaluation, path proposal, description generation) are performed server-side
-  - Handle graceful degradation at each failure point: content analysis failure skips the entire search pipeline (memo-only), candidate evaluation failure falls back to memo + category (if available), category failure is independent and does not affect the search pipeline
-  - Ensure the response always contains at least one suggestion (memo type)
-  - Update the route handler to use the revised orchestration function with injected dependencies
-  - Include unit tests for: full pipeline success with all suggestion types, partial failures at each stage with correct degradation, informationType mapping to PathSuggestion, dependency injection, and parallel execution of category vs search-evaluate pipeline
-  - _Requirements: 1.1, 1.2, 1.3, 3.3, 3.4, 5.3, 5.5, 8.3, 9.2, 11.4, 13.1, 13.2, 13.3_
-
 - [x] 7.2 Phase 2 integration verification
 - [x] 7.2 Phase 2 integration verification
-  - Verify the complete revised flow end-to-end: content body → content analysis (keywords + informationType) → search candidate retrieval (with score threshold) → candidate evaluation (path proposals + descriptions) → grant resolution → unified response with all suggestion types
-  - Verify informationType field is present in search-based suggestions and absent in memo and category suggestions
-  - Verify path proposal patterns work correctly: parent directory, subdirectory, and sibling with generated new paths at the correct hierarchy level
-  - Verify graceful degradation at each failure point: content analysis failure → memo-only, search returns empty → search suggestions omitted, candidate evaluation failure → memo + category, category failure → memo + search, all Phase 2 failures → memo-only
-  - Verify response structure across all suggestion types: correct fields, AI-generated descriptions for search type, fixed description for memo, mechanical description for category, valid grant values, and trailing slashes on all paths
-  - _Requirements: 3.1, 3.2, 3.3, 3.4, 3.5, 5.1, 5.4, 5.5, 6.1, 6.3, 10.1, 11.1, 11.4, 12.1, 13.1, 13.2_
 
 
 ## Post-Implementation Refactoring (from code review)
 ## Post-Implementation Refactoring (from code review)
 
 
@@ -105,27 +24,9 @@ See `gap-analysis.md` for detailed rationale.
 
 
 - [x] 8. Simplify service layer abstractions
 - [x] 8. Simplify service layer abstractions
 - [x] 8.1 Remove `GenerateSuggestionsDeps` DI pattern from `generate-suggestions.ts`
 - [x] 8.1 Remove `GenerateSuggestionsDeps` DI pattern from `generate-suggestions.ts`
-  - Remove the `GenerateSuggestionsDeps` type and `deps` parameter from `generateSuggestions()`
-  - Import `analyzeContent`, `evaluateCandidates`, `generateCategorySuggestion`, `resolveParentGrant` directly
-  - Accept `searchService` as a direct argument (the only true external dependency that cannot be imported)
-  - Rewrite `generate-suggestions.spec.ts` to use `vi.mock()` instead of injected mock deps
-  - Simplify the route handler in `routes/apiv3/index.ts` to pass `searchService` directly instead of wiring 5 callbacks
-
 - [x] 8.2 Remove `RetrieveSearchCandidatesOptions` from `retrieve-search-candidates.ts`
 - [x] 8.2 Remove `RetrieveSearchCandidatesOptions` from `retrieve-search-candidates.ts`
-  - Replace `options: RetrieveSearchCandidatesOptions` with a direct `searchService: SearchService` parameter
-  - Keep `scoreThreshold` as a module-level constant (no caller overrides it)
-  - Update `retrieve-search-candidates.spec.ts` accordingly
-  - Update the call site in `generate-suggestions.ts` (no more lambda wrapper needed)
-
 - [x] 8.3 Add JSDoc to `call-llm-for-json.ts`
 - [x] 8.3 Add JSDoc to `call-llm-for-json.ts`
-  - Add a brief JSDoc comment explaining this utility's purpose: shared LLM client initialization, JSON parsing, and response validation
-  - Document that it is consumed by `analyzeContent` and `evaluateCandidates`
-
 - [x] 8.4 Narrow `userGroups: unknown` to `ObjectIdLike[]`
 - [x] 8.4 Narrow `userGroups: unknown` to `ObjectIdLike[]`
-  - Update `SearchService` interface in `suggest-path-types.ts`: change `userGroups: unknown` to `userGroups: ObjectIdLike[]`
-  - Propagate the type change to `retrieveSearchCandidates` and `generateSuggestions` signatures
-  - Import `ObjectIdLike` from `@growi/core` (or the appropriate subpath)
-  - Update test files to use correctly typed mock values
 
 
 ## Requirements Coverage
 ## Requirements Coverage
 
 

+ 0 - 262
.kiro/specs/upgrade-fixed-packages/design.md

@@ -1,262 +0,0 @@
-# Design Document: upgrade-fixed-packages
-
-## Overview
-
-**Purpose**: This feature audits and upgrades version-pinned packages in `apps/app/package.json` that were frozen due to upstream bugs, ESM-only migrations, or licensing constraints. The build environment has shifted from webpack to Turbopack, and the runtime now targets Node.js 24 with stable `require(esm)` support, invalidating several original pinning reasons.
-
-**Users**: Maintainers and developers benefit from up-to-date dependencies with bug fixes, security patches, and reduced technical debt.
-
-**Impact**: Modifies `apps/app/package.json` dependency versions and comment blocks; touches source files where `escape-string-regexp` is replaced by native `RegExp.escape()`.
-
-### Goals
-- Verify each pinning reason against current upstream status
-- Upgrade packages where the original constraint no longer applies
-- Replace `escape-string-regexp` with native `RegExp.escape()` (Node.js 24)
-- Update or remove comment blocks to reflect current state
-- Produce audit documentation for future reference
-
-### Non-Goals
-- Replacing handsontable with an alternative library (license constraint remains; replacement is a separate initiative)
-- Upgrading `@keycloak/keycloak-admin-client` to v19+ (significant API breaking changes; deferred to separate task)
-- Major version upgrades of unrelated packages
-- Modifying the build pipeline or Turbopack configuration
-
-## Architecture
-
-This is a dependency maintenance task, not a feature implementation. No new components or architectural changes are introduced.
-
-### Existing Architecture Analysis
-
-The pinned packages fall into distinct categories by their usage context:
-
-| Category | Packages | Build Context |
-|----------|----------|---------------|
-| Server-only (tsc → CJS) | `escape-string-regexp`, `@aws-sdk/*`, `@keycloak/*` | Express server compiled by tsc |
-| Client-only (Turbopack) | `string-width` (via @growi/editor), `bootstrap` | Bundled by Turbopack/Vite |
-| Client + SSR | `next-themes` | Turbopack + SSR rendering |
-| License-pinned | `handsontable`, `@handsontable/react` | Client-only |
-
-Key enabler: Node.js ^24 provides stable `require(esm)` support, removing the fundamental CJS/ESM incompatibility that caused several pins.
-
-### Technology Stack
-
-| Layer | Choice / Version | Role in Feature | Notes |
-|-------|------------------|-----------------|-------|
-| Runtime | Node.js ^24 | Enables `require(esm)` and `RegExp.escape()` | ES2026 Stage 4 features available |
-| Build (client) | Turbopack (Next.js 16) | Bundles ESM-only packages without issues | No changes needed |
-| Build (server) | tsc (CommonJS output) | `require(esm)` handles ESM-only imports | Node.js 24 native support |
-| Package manager | pnpm v10 | Manages dependency resolution | No changes needed |
-
-## System Flows
-
-### Upgrade Verification Flow
-
-```mermaid
-flowchart TD
-    Start[Select package to upgrade] --> Update[Update version in package.json]
-    Update --> Install[pnpm install]
-    Install --> Build{turbo run build}
-    Build -->|Pass| Lint{turbo run lint}
-    Build -->|Fail| Revert[Revert package change]
-    Lint -->|Pass| Test{turbo run test}
-    Lint -->|Fail| Revert
-    Test -->|Pass| Verify[Verify .next/node_modules symlinks]
-    Test -->|Fail| Revert
-    Verify --> Next[Proceed to next package]
-    Revert --> Document[Document failure reason]
-    Document --> Next
-```
-
-Each package is upgraded and verified independently. Failures are isolated and reverted without affecting other upgrades.
-
-## Requirements Traceability
-
-| Requirement | Summary | Components | Action |
-|-------------|---------|------------|--------|
-| 1.1 | Bootstrap bug investigation | PackageAudit | Verify #39798 fixed in v5.3.4 |
-| 1.2 | next-themes issue investigation | PackageAudit | Verify #122 resolved; check v0.4.x compatibility |
-| 1.3 | @aws-sdk constraint verification | PackageAudit | Confirm mongodb constraint is on different package |
-| 1.4 | Document investigation results | AuditReport | Summary table in research.md |
-| 2.1 | ESM compatibility per package | PackageAudit | Assess escape-string-regexp, string-width, @keycloak |
-| 2.2 | Server build ESM support | PackageAudit | Verify Node.js 24 require(esm) for server context |
-| 2.3 | Client build ESM support | PackageAudit | Confirm Turbopack handles ESM-only packages |
-| 2.4 | Compatibility matrix | AuditReport | Table in research.md |
-| 3.1 | Handsontable license check | PackageAudit | Confirm v7+ still non-MIT |
-| 3.2 | Document pinning requirement | AuditReport | Note in audit summary |
-| 4.1 | Update package.json versions and comments | UpgradeExecution | Modify versions and comment blocks |
-| 4.2 | Build verification | UpgradeExecution | `turbo run build --filter @growi/app` |
-| 4.3 | Lint verification | UpgradeExecution | `turbo run lint --filter @growi/app` |
-| 4.4 | Test verification | UpgradeExecution | `turbo run test --filter @growi/app` |
-| 4.5 | Revert on failure | UpgradeExecution | Git revert per package |
-| 4.6 | Update comment blocks | UpgradeExecution | Remove or update comments |
-| 5.1 | Audit summary table | AuditReport | Final summary with decisions |
-| 5.2 | Document continued pinning | AuditReport | Reasons for remaining pins |
-| 5.3 | Document upgrade rationale | AuditReport | What changed upstream |
-
-## Components and Interfaces
-
-| Component | Domain | Intent | Req Coverage | Key Dependencies |
-|-----------|--------|--------|--------------|------------------|
-| PackageAudit | Investigation | Research upstream status for each pinned package | 1.1–1.4, 2.1–2.4, 3.1–3.2 | GitHub issues, npm registry |
-| UpgradeExecution | Implementation | Apply version changes and verify build | 4.1–4.6 | pnpm, turbo, tsc |
-| SourceMigration | Implementation | Replace escape-string-regexp with RegExp.escape() | 4.1 | 9 source files |
-| AuditReport | Documentation | Produce summary of all decisions | 5.1–5.3 | research.md |
-
-### Investigation Layer
-
-#### PackageAudit
-
-| Field | Detail |
-|-------|--------|
-| Intent | Investigate upstream status of each pinned package and determine upgrade feasibility |
-| Requirements | 1.1, 1.2, 1.3, 1.4, 2.1, 2.2, 2.3, 2.4, 3.1, 3.2 |
-
-**Responsibilities & Constraints**
-- Check upstream issue trackers for bug fix status
-- Verify ESM compatibility against Node.js 24 `require(esm)` and Turbopack
-- Confirm license status for handsontable
-- Produce actionable recommendation per package
-
-**Audit Decision Matrix**
-
-| Package | Current | Action | Target | Risk | Rationale |
-|---------|---------|--------|--------|------|-----------|
-| `bootstrap` | `=5.3.2` | Upgrade | `^5.3.4` | Low | Bug #39798 fixed in v5.3.4 |
-| `next-themes` | `^0.2.1` | Upgrade | `^0.4.4` | Medium | Original issue was misattributed; v0.4.x works with Pages Router |
-| `escape-string-regexp` | `^4.0.0` | Replace | Remove dep | Low | Native `RegExp.escape()` in Node.js 24 |
-| `string-width` | `=4.2.2` | Upgrade | `^7.0.0` | Low | Used only in ESM context (@growi/editor) |
-| `@aws-sdk/client-s3` | `3.454.0` | Relax | `^3.454.0` | Low | Pinning comment was misleading |
-| `@aws-sdk/s3-request-presigner` | `3.454.0` | Relax | `^3.454.0` | Low | Same as above |
-| `@keycloak/keycloak-admin-client` | `^18.0.0` | Defer | No change | N/A | API breaking changes; separate task |
-| `handsontable` | `=6.2.2` | Keep | No change | N/A | License constraint (non-MIT since v7) |
-| `@handsontable/react` | `=2.1.0` | Keep | No change | N/A | Requires handsontable >= 7 |
-
-### Implementation Layer
-
-#### UpgradeExecution
-
-| Field | Detail |
-|-------|--------|
-| Intent | Apply version changes incrementally with build verification |
-| Requirements | 4.1, 4.2, 4.3, 4.4, 4.5, 4.6 |
-
-**Responsibilities & Constraints**
-- Upgrade one package at a time to isolate failures
-- Run full verification suite (build, lint, test) after each change
-- Revert and document any package that causes failures
-- Update `// comments for dependencies` block to reflect new state
-
-**Upgrade Order** (lowest risk first):
-1. `@aws-sdk/*` — relax version range (no code changes)
-2. `string-width` — upgrade in @growi/editor (isolated ESM package)
-3. `bootstrap` — upgrade to ^5.3.4 (verify SCSS compilation)
-4. `escape-string-regexp` → `RegExp.escape()` — source code changes across 9 files
-5. `next-themes` — upgrade to ^0.4.x (review API changes across 12 files)
-
-**Implementation Notes**
-- After each upgrade, verify `.next/node_modules/` symlinks for Turbopack externalisation compliance (per `package-dependencies` rule)
-- For bootstrap: run `pnpm run pre:styles-commons` and `pnpm run pre:styles-components` to verify SCSS compilation
-- For next-themes: review v0.3.0 and v0.4.0 changelogs for breaking API changes before modifying code
-
-#### SourceMigration
-
-| Field | Detail |
-|-------|--------|
-| Intent | Replace all `escape-string-regexp` usage with native `RegExp.escape()` |
-| Requirements | 4.1 |
-
-**Files to Modify**:
-
-`apps/app/src/` (6 files):
-- `server/models/page.ts`
-- `server/service/page/index.ts`
-- `server/service/page-grant.ts`
-- `server/routes/apiv3/users.js`
-- `server/models/obsolete-page.js`
-- `features/openai/server/services/openai.ts`
-
-`packages/` (3 files):
-- `packages/core/src/utils/page-path-utils/` (2 files)
-- `packages/remark-lsx/src/server/routes/list-pages/index.ts`
-
-**Migration Pattern**:
-```typescript
-// Before
-import escapeStringRegexp from 'escape-string-regexp';
-const pattern = new RegExp(escapeStringRegexp(input));
-
-// After
-const pattern = new RegExp(RegExp.escape(input));
-```
-
-**Implementation Notes**
-- Remove `escape-string-regexp` from `apps/app/package.json` dependencies after migration
-- Remove from `packages/core/package.json` and `packages/remark-lsx/package.json` if listed
-- Verify `RegExp.escape()` TypeScript types are available (may need `@types/node` update or lib config)
-
-### Documentation Layer
-
-#### AuditReport
-
-| Field | Detail |
-|-------|--------|
-| Intent | Document all audit decisions for future maintainers |
-| Requirements | 5.1, 5.2, 5.3 |
-
-**Deliverables**:
-- Updated `// comments for dependencies` in package.json (only retained pins with current reasons)
-- Updated `// comments for defDependencies` (handsontable entries unchanged)
-- Summary in research.md with final decision per package
-
-**Updated Comment Blocks** (target state):
-
-```json
-{
-  "// comments for dependencies": {
-    "@keycloak/keycloak-admin-client": "19.0.0 or above exports only ESM. API breaking changes require separate migration effort.",
-    "next-themes": "(if upgrade fails) Document specific failure reason here"
-  },
-  "// comments for defDependencies": {
-    "@handsontable/react": "v3 requires handsontable >= 7.0.0.",
-    "handsontable": "v7.0.0 or above is no longer MIT license."
-  }
-}
-```
-
-Note: The exact final state depends on which upgrades succeed. If all planned upgrades pass, only `@keycloak` and `handsontable` entries remain.
-
-## Testing Strategy
-
-### Build Verification (per package)
-- `turbo run build --filter @growi/app` — Turbopack client build + tsc server build
-- `ls apps/app/.next/node_modules/ | grep <package>` — Externalisation check
-- `pnpm run pre:styles-commons` — SCSS compilation (bootstrap only)
-
-### Lint Verification (per package)
-- `turbo run lint --filter @growi/app` — TypeScript type check + Biome
-
-### Unit/Integration Tests (per package)
-- `turbo run test --filter @growi/app` — Full test suite
-- For `RegExp.escape()` migration: run tests for page model, page service, page-grant service specifically
-
-### Regression Verification (final)
-- Full build + lint + test after all upgrades applied together
-- Verify `.next/node_modules/` symlink integrity via `check-next-symlinks.sh` (if available locally)
-
-## Migration Strategy
-
-```mermaid
-flowchart LR
-    Phase1[Phase 1: Low Risk] --> Phase2[Phase 2: Medium Risk]
-    Phase1 --> P1a[aws-sdk relax range]
-    Phase1 --> P1b[string-width upgrade]
-    Phase2 --> P2a[bootstrap upgrade]
-    Phase2 --> P2b[escape-string-regexp replace]
-    Phase2 --> P2c[next-themes upgrade]
-```
-
-- **Phase 1** (low risk): @aws-sdk range relaxation, string-width upgrade — minimal code changes
-- **Phase 2** (medium risk): bootstrap, escape-string-regexp replacement, next-themes — requires code review and/or source changes
-- Each upgrade is independently revertible
-- Deferred: @keycloak (high risk, separate task)
-- No change: handsontable (license constraint)

+ 0 - 75
.kiro/specs/upgrade-fixed-packages/requirements.md

@@ -1,75 +0,0 @@
-# Requirements Document
-
-## Introduction
-
-The `apps/app/package.json` file contains several packages whose versions are intentionally pinned due to ESM-only upgrades, upstream bugs, or licensing concerns. These pinning reasons were documented in `// comments for dependencies` and `// comments for defDependencies` comment blocks. Since the build environment has significantly changed (webpack → Turbopack), and upstream issues may have been resolved, a systematic audit is needed to determine which packages can now be safely upgraded.
-
-### Pinned Packages Inventory
-
-| # | Package | Current Version | Pinning Reason |
-|---|---------|----------------|----------------|
-| 1 | `@aws-sdk/client-s3`, `@aws-sdk/s3-request-presigner` | `3.454.0` | Fix version above 3.186.0 required by mongodb@4.16.0 |
-| 2 | `@keycloak/keycloak-admin-client` | `^18.0.0` | 19.0.0+ exports only ESM |
-| 3 | `bootstrap` | `=5.3.2` | v5.3.3 has a bug (twbs/bootstrap#39798) |
-| 4 | `escape-string-regexp` | `^4.0.0` | 5.0.0+ exports only ESM |
-| 5 | `next-themes` | `^0.2.1` | 0.3.0 causes type error (pacocoursey/next-themes#122) |
-| 6 | `string-width` | `=4.2.2` | 5.0.0+ exports only ESM |
-| 7 | `@handsontable/react` | `=2.1.0` | v3 requires handsontable >= 7.0.0 |
-| 8 | `handsontable` | `=6.2.2` | v7.0.0+ is no longer MIT license |
-
-## Requirements
-
-### Requirement 1: Upstream Bug and Issue Investigation
-
-**Objective:** As a maintainer, I want to verify whether upstream bugs and issues that originally caused version pinning have been resolved, so that I can make informed upgrade decisions.
-
-#### Acceptance Criteria
-
-1. When investigating the bootstrap pinning, the audit process shall check the current status of https://github.com/twbs/bootstrap/issues/39798 and determine whether v5.3.3+ has fixed the reported bug.
-2. When investigating the next-themes pinning, the audit process shall check the current status of https://github.com/pacocoursey/next-themes/issues/122 and determine whether v0.3.0+ has resolved the type error.
-3. When investigating the @aws-sdk pinning, the audit process shall verify whether the mongodb version used in GROWI still requires the `>=3.186.0` constraint and whether the latest @aws-sdk versions are compatible.
-4. The audit process shall document the investigation result for each package, including: current upstream status, whether the original issue is resolved, and the recommended action (upgrade/keep/replace).
-
-### Requirement 2: ESM-Only Package Compatibility Assessment
-
-**Objective:** As a maintainer, I want to assess whether ESM-only versions of pinned packages are now compatible with the current Turbopack-based build environment, so that outdated CJS-only constraints can be removed.
-
-#### Acceptance Criteria
-
-1. When assessing ESM compatibility, the audit process shall evaluate each ESM-pinned package (`escape-string-regexp`, `string-width`, `@keycloak/keycloak-admin-client`) against the current build pipeline (Turbopack for client, tsc for server).
-2. When a package is used in server-side code (transpiled via tsc with `tsconfig.build.server.json`), the audit process shall verify whether the server build output format (CJS or ESM) supports importing ESM-only packages.
-3. When a package is used only in client-side code (bundled via Turbopack), the audit process shall confirm that Turbopack can resolve ESM-only packages without issues.
-4. The audit process shall produce a compatibility matrix showing each ESM-pinned package, its usage context (server/client/both), and whether upgrading to the ESM-only version is feasible.
-
-### Requirement 3: License Compliance Verification
-
-**Objective:** As a maintainer, I want to confirm that the handsontable/`@handsontable/react` licensing situation has not changed, so that I can determine whether these packages must remain pinned or can be replaced.
-
-#### Acceptance Criteria
-
-1. When evaluating handsontable, the audit process shall verify the current license of handsontable v7.0.0+ and confirm whether it remains non-MIT.
-2. If handsontable v7.0.0+ is still non-MIT, the audit process shall document that `handsontable` (`=6.2.2`) and `@handsontable/react` (`=2.1.0`) must remain pinned or an alternative library must be identified.
-3. If a MIT-licensed alternative to handsontable exists, the audit process shall note it as a potential replacement candidate (out of scope for this spec but documented for future work).
-
-### Requirement 4: Safe Upgrade Execution
-
-**Objective:** As a maintainer, I want to upgrade packages that are confirmed safe to update, so that the project benefits from bug fixes, security patches, and new features.
-
-#### Acceptance Criteria
-
-1. When upgrading a pinned package, the upgrade process shall update the version specifier in `apps/app/package.json` and remove or update the corresponding entry in the `// comments for dependencies` or `// comments for defDependencies` block.
-2. When a package is upgraded, the upgrade process shall verify that `turbo run build --filter @growi/app` completes successfully.
-3. When a package is upgraded, the upgrade process shall verify that `turbo run lint --filter @growi/app` completes without new errors.
-4. When a package is upgraded, the upgrade process shall verify that `turbo run test --filter @growi/app` passes without new failures.
-5. If a package upgrade causes build, lint, or test failures, the upgrade process shall revert that specific package change and document the failure reason.
-6. When all upgrades are complete, the `// comments for dependencies` and `// comments for defDependencies` blocks shall accurately reflect only the packages that remain pinned, with updated reasons if applicable.
-
-### Requirement 5: Audit Documentation
-
-**Objective:** As a maintainer, I want a clear record of the audit results, so that future maintainers understand which packages were evaluated and why decisions were made.
-
-#### Acceptance Criteria
-
-1. The audit process shall produce a summary table documenting each pinned package with: package name, previous version, new version (or "unchanged"), and rationale for the decision.
-2. When a package remains pinned, the documentation shall include the verified reason for continued pinning.
-3. When a package is upgraded, the documentation shall note what changed upstream that made the upgrade possible.

+ 0 - 183
.kiro/specs/upgrade-fixed-packages/research.md

@@ -1,183 +0,0 @@
-# Research & Design Decisions
-
----
-**Purpose**: Capture discovery findings for the pinned package audit and upgrade initiative.
-**Usage**: Inform design.md decisions; provide evidence for future maintainers.
----
-
-## Summary
-- **Feature**: `upgrade-fixed-packages`
-- **Discovery Scope**: Extension (auditing existing dependency constraints)
-- **Key Findings**:
-  - Bootstrap bug (#39798) fixed in v5.3.4 — safe to upgrade to latest 5.3.x
-  - next-themes original issue (#122) was resolved long ago; upgrade to v0.4.x feasible but has Next.js 16 `cacheComponents` caveat
-  - Node.js ^24 enables stable `require(esm)`, unlocking ESM-only package upgrades for server code
-  - `escape-string-regexp` can be replaced entirely by native `RegExp.escape()` (ES2026, Node.js 24)
-  - handsontable license situation unchanged — must remain pinned at 6.2.2
-  - @aws-sdk pinning comment is misleading; packages can be freely upgraded
-
-## Research Log
-
-### Bootstrap v5.3.3 Bug (#39798)
-- **Context**: bootstrap pinned at `=5.3.2` due to modal header regression in v5.3.3
-- **Sources Consulted**: https://github.com/twbs/bootstrap/issues/39798, https://github.com/twbs/bootstrap/pull/41336
-- **Findings**:
-  - Issue CLOSED on 2025-04-03
-  - Fixed in v5.3.4 via PR #41336 (Fix modal and offcanvas header collapse)
-  - Bug: `.modal-header` lost `justify-content: space-between`, causing content collapse
-  - Latest stable: v5.3.8 (August 2025)
-- **Implications**: Safe to upgrade from `=5.3.2` to `^5.3.4`. Skip v5.3.3 entirely. Recommend `^5.3.4` or pin to latest `=5.3.8`.
-
-### next-themes Type Error (#122)
-- **Context**: next-themes pinned at `^0.2.1` due to reported type error in v0.3.0
-- **Sources Consulted**: https://github.com/pacocoursey/next-themes/issues/122, https://github.com/pacocoursey/next-themes/issues/375
-- **Findings**:
-  - Issue #122 CLOSED on 2022-06-02 — was specific to an old beta version (v0.0.13-beta.3), not v0.3.0
-  - The pinning reason was based on incomplete information; v0.2.0+ already had the fix
-  - Latest: v0.4.6 (March 2025). Peers: `react ^16.8 || ^17 || ^18 || ^19`
-  - **Caveat**: Issue #375 reports a bug with Next.js 16's `cacheComponents` feature — stale theme values when cached components reactivate
-  - PR #377 in progress to fix via `useSyncExternalStore`
-  - Without `cacheComponents`, v0.4.6 works fine with Next.js 16
-- **Implications**: Upgrade to v0.4.x is feasible. GROWI uses Pages Router (not App Router), so `cacheComponents` is likely not relevant. Breaking API changes between v0.2 → v0.4 need review. Used in 12 files across apps/app.
-
-### ESM-only Package Compatibility (escape-string-regexp, string-width, @keycloak)
-- **Context**: Three packages pinned to CJS-compatible versions because newer versions are ESM-only
-- **Sources Consulted**: Node.js v22.12.0 release notes (require(esm) enabled by default), TC39 RegExp.escape Stage 4, sindresorhus ESM guidance, npm package pages
-- **Findings**:
-
-  **escape-string-regexp** (^4.0.0):
-  - Used in 6 server-side files + 3 shared package files (all server context)
-  - Node.js 24 has stable `require(esm)` — ESM-only v5 would work
-  - **Better**: `RegExp.escape()` is ES2026 Stage 4, natively available in Node.js 24 (V8 support)
-  - Can eliminate the dependency entirely
-
-  **string-width** (=4.2.2):
-  - Used only in `packages/editor/src/models/markdown-table.js`
-  - `@growi/editor` has `"type": "module"` and builds with Vite (ESM context)
-  - No server-side value imports (only type imports in `sync-ydoc.ts`, erased at compile)
-  - Safe to upgrade to v7.x
-
-  **@keycloak/keycloak-admin-client** (^18.0.0):
-  - Used in 1 server-side file: `features/external-user-group/server/service/keycloak-user-group-sync.ts`
-  - Latest: v26.5.5 (February 2026)
-  - `require(esm)` in Node.js 24 should handle it, but API has significant breaking changes (v18 → v26)
-  - Sub-path exports need verification
-  - Higher risk upgrade — API surface changes expected
-
-- **Implications**: string-width is the easiest upgrade. escape-string-regexp should be replaced by native `RegExp.escape()`. @keycloak requires careful API migration and is higher risk.
-
-### @aws-sdk Pinning Analysis
-- **Context**: @aws-sdk/client-s3 and @aws-sdk/s3-request-presigner pinned at 3.454.0
-- **Sources Consulted**: mongodb package.json, npm registry, GROWI source code
-- **Findings**:
-  - Pinning comment says "required by mongodb@4.16.0" but is misleading
-  - mongodb@4.17.2 has `@aws-sdk/credential-providers: ^3.186.0` as **optional** dependency — a different package
-  - The S3 client packages are used directly by GROWI for file upload (server/service/file-uploader/aws/)
-  - Latest: @aws-sdk/client-s3@3.1014.0 (March 2026) — over 500 versions behind
-  - AWS SDK v3 follows semver; any 3.x should be compatible
-- **Implications**: Remove the misleading comment. Change from exact `3.454.0` to `^3.454.0` or update to latest. Low risk.
-
-### Handsontable License Status
-- **Context**: handsontable pinned at =6.2.2 (last MIT version), @handsontable/react at =2.1.0
-- **Sources Consulted**: handsontable.com/docs/software-license, npm, Hacker News discussion
-- **Findings**:
-  - v7.0.0+ (March 2019) switched from MIT to proprietary license — unchanged as of 2026
-  - Free "Hobby" license exists but restricted to non-commercial personal use
-  - Commercial use requires paid subscription
-  - MIT alternatives: AG Grid Community (most mature), Jspreadsheet CE, Univer (Apache 2.0)
-- **Implications**: Must remain pinned. No action possible without license purchase or library replacement. Library replacement is out of scope for this spec.
-
-## Design Decisions
-
-### Decision: Replace escape-string-regexp with native RegExp.escape()
-- **Context**: escape-string-regexp v5 is ESM-only; used in 9 files across server code
-- **Alternatives Considered**:
-  1. Upgrade to v5 with require(esm) support — works but adds unnecessary dependency
-  2. Replace with native `RegExp.escape()` — zero dependencies, future-proof
-- **Selected Approach**: Replace with `RegExp.escape()`
-- **Rationale**: Node.js 24 supports `RegExp.escape()` natively (ES2026 Stage 4). Eliminates a dependency entirely.
-- **Trade-offs**: Requires touching 9 files, but changes are mechanical (find-and-replace)
-- **Follow-up**: Verify `RegExp.escape()` is available in the project's Node.js 24 target
-
-### Decision: Upgrade string-width directly to v7.x
-- **Context**: Used only in @growi/editor (ESM package, Vite-bundled, client-only)
-- **Selected Approach**: Direct upgrade to latest v7.x
-- **Rationale**: Consumer is already ESM; zero CJS concern
-- **Trade-offs**: None significant; API is stable
-
-### Decision: Upgrade bootstrap to ^5.3.4
-- **Context**: Bug fixed in v5.3.4; latest is 5.3.8
-- **Selected Approach**: Change from `=5.3.2` to `^5.3.4`
-- **Rationale**: Original bug resolved; skip v5.3.3
-- **Trade-offs**: Need to verify GROWI's custom SCSS and modal usage against 5.3.4+ changes
-
-### Decision: Upgrade next-themes to latest 0.4.x
-- **Context**: Original issue was a misunderstanding; latest is v0.4.6
-- **Selected Approach**: Upgrade to `^0.4.4` (or latest)
-- **Rationale**: Issue #122 was specific to old beta, not v0.3.0. GROWI uses Pages Router, so cacheComponents bug is not relevant.
-- **Trade-offs**: Breaking API changes between v0.2 → v0.4 need review. 12 files import from next-themes.
-- **Follow-up**: Review v0.3.0 and v0.4.0 changelogs for breaking changes
-
-### Decision: Relax @aws-sdk version to caret range
-- **Context**: Pinning was based on misleading comment; packages are independent of mongodb constraint
-- **Selected Approach**: Change from `3.454.0` to `^3.454.0`
-- **Rationale**: AWS SDK v3 follows semver; the comment conflated credential-providers with S3 client
-- **Trade-offs**: Low risk. Conservative approach keeps minimum at 3.454.0.
-
-### Decision: Defer @keycloak upgrade (high risk)
-- **Context**: v18 → v26 has significant API breaking changes; only 1 file affected
-- **Selected Approach**: Document as upgradeable but defer to a separate task
-- **Rationale**: API migration requires Keycloak server compatibility testing; out of proportion for a batch upgrade task
-- **Trade-offs**: Remains on old version longer, but isolated to one feature
-
-### Decision: Keep handsontable pinned (license constraint)
-- **Context**: v7+ is proprietary; no free alternative that's drop-in
-- **Selected Approach**: No change. Document for future reference.
-- **Rationale**: License constraint is permanent unless library is replaced entirely
-- **Trade-offs**: None — this is a business/legal decision, not technical
-
-## Risks & Mitigations
-- **Bootstrap SCSS breakage**: v5.3.4+ may have SCSS variable changes → Run `pre:styles-commons` and `pre:styles-components` builds to verify
-- **next-themes API changes**: v0.2 → v0.4 has breaking changes → Review changelog; test all 12 consuming files
-- **RegExp.escape() availability**: Ensure Node.js 24 V8 includes it → Verify with simple runtime test
-- **@aws-sdk transitive dependency changes**: Newer AWS SDK may pull different transitive deps → Monitor bundle size
-- **Build regression**: Any upgrade could break Turbopack build → Follow incremental upgrade strategy with build verification per package
-
-## Future Considerations (Out of Scope)
-
-### transpilePackages cleanup in next.config.ts
-- **Context**: `next.config.ts` defines `getTranspilePackages()` listing 60+ ESM-only packages to force Turbopack to bundle them instead of externalising. The original comment says: "listing ESM packages until experimental.esmExternals works correctly to avoid ERR_REQUIRE_ESM".
-- **Relationship to require(esm)**: `transpilePackages` and `require(esm)` solve different problems. `transpilePackages` prevents Turbopack from externalising packages during SSR; `require(esm)` allows Node.js to load ESM packages via `require()` at runtime. With Node.js 24's stable `require(esm)`, externalised ESM packages *should* load correctly in SSR, meaning some `transpilePackages` entries may become unnecessary.
-- **Why not now**: (1) Turbopack's `esmExternals` handling is still `experimental`; (2) removing entries shifts packages from bundled to externalised, which means they appear in `.next/node_modules/` and must be classified as `dependencies` per the `package-dependencies` rule; (3) 60+ packages need individual verification. This is a separate investigation with a large blast radius.
-- **Recommendation**: Track as a separate task. Test by removing a few low-risk entries (e.g., `bail`, `ccount`, `zwitch`) and checking whether SSR still works with Turbopack externalisation + Node.js 24 `require(esm)`.
-
-## References
-- [Bootstrap issue #39798](https://github.com/twbs/bootstrap/issues/39798) — modal header regression, fixed in v5.3.4
-- [next-themes issue #122](https://github.com/pacocoursey/next-themes/issues/122) — type error, resolved in v0.2.0
-- [next-themes issue #375](https://github.com/pacocoursey/next-themes/issues/375) — Next.js 16 cacheComponents bug
-- [TC39 RegExp.escape() Stage 4](https://socket.dev/blog/tc39-advances-3-proposals-to-stage-4-regexp-escaping-float16array-and-redeclarable-global-eval) — ES2026
-- [Node.js require(esm) stability](https://joyeecheung.github.io/blog/2025/12/30/require-esm-in-node-js-from-experiment-to-stability/) — stable since Node.js 22.12.0
-- [Handsontable license change](https://handsontable.com/docs/javascript-data-grid/software-license/) — proprietary since v7.0.0
-
-## Final Audit Summary (2026-03-23)
-
-| Package | Previous Version | New Version | Action | Rationale |
-|---------|-----------------|-------------|--------|-----------|
-| `@aws-sdk/client-s3` | `3.454.0` | `^3.1014.0` | Upgraded | Pinning comment was misleading; S3 client is independent of mongodb constraint |
-| `@aws-sdk/s3-request-presigner` | `3.454.0` | `^3.1014.0` | Upgraded | Same as above |
-| `bootstrap` | `=5.3.2` | `^5.3.8` | Upgraded | Bug #39798 fixed in v5.3.4; SCSS compilation verified |
-| `escape-string-regexp` | `^4.0.0` | Removed | Replaced | Native `RegExp.escape()` (ES2026, Node.js 24) eliminates the dependency |
-| `string-width` | `=4.2.2` | `^7.0.0` | Upgraded | Used only in @growi/editor (ESM context, Vite-bundled) |
-| `next-themes` | `^0.2.1` | `^0.4.6` | Upgraded | Original issue #122 was misattributed; only change needed: type import path |
-| `@keycloak/keycloak-admin-client` | `^18.0.0` | Unchanged | Deferred | API breaking changes (v18→v26) require separate migration effort |
-| `handsontable` | `=6.2.2` | Unchanged | Kept | v7.0.0+ is proprietary (non-MIT license) |
-| `@handsontable/react` | `=2.1.0` | Unchanged | Kept | Requires handsontable >= 7.0.0 |
-
-### Additional Changes
-
-- Added `RegExp.escape()` TypeScript type declarations in `apps/app/src/@types/`, `packages/core/src/@types/`, and `packages/remark-lsx/src/@types/` (awaiting TypeScript built-in support)
-- Updated `tsconfig.build.client.json` to include `src/@types/**/*.d.ts` for Next.js build compatibility
-- Updated `generate-children-regexp.spec.ts` test expectations for `RegExp.escape()` output (escapes spaces as `\x20`)
-- Removed `escape-string-regexp` from `transpilePackages` in `next.config.ts`
-- Updated `bootstrap` version across 5 packages: apps/app, packages/editor, packages/core-styles, packages/preset-themes, apps/slackbot-proxy
-- Updated `// comments for dependencies` to retain only `@keycloak` entry with updated reason

+ 0 - 22
.kiro/specs/upgrade-fixed-packages/spec.json

@@ -1,22 +0,0 @@
-{
-  "feature_name": "upgrade-fixed-packages",
-  "created_at": "2026-03-23T00:00:00Z",
-  "updated_at": "2026-03-23T00:00:00Z",
-  "language": "en",
-  "phase": "implementation-complete",
-  "approvals": {
-    "requirements": {
-      "generated": true,
-      "approved": true
-    },
-    "design": {
-      "generated": true,
-      "approved": true
-    },
-    "tasks": {
-      "generated": true,
-      "approved": true
-    }
-  },
-  "ready_for_implementation": true
-}

+ 0 - 89
.kiro/specs/upgrade-fixed-packages/tasks.md

@@ -1,89 +0,0 @@
-# Implementation Plan
-
-- [x] 1. Pre-implementation verification
-- [x] 1.1 Verify RegExp.escape() availability and TypeScript support
-  - Confirm `RegExp.escape()` is available at runtime in the project's Node.js 24 target
-  - Check whether TypeScript recognizes `RegExp.escape()` — may need `lib` config update or `@types/node` update
-  - If unavailable, fall back to upgrading `escape-string-regexp` to v5 with `require(esm)` instead
-  - _Requirements: 2.2_
-
-- [x] 1.2 Review next-themes v0.3.0 and v0.4.0 breaking API changes
-  - Read changelogs for v0.3.0 and v0.4.0 releases to identify breaking changes
-  - Map breaking changes to the 12 consuming files in apps/app
-  - Determine migration effort and document required code changes
-  - Confirm GROWI's Pages Router usage is unaffected by the cacheComponents bug (issue #375)
-  - _Requirements: 1.2_
-
-- [x] 2. Low-risk package upgrades
-- [x] 2.1 (P) Relax @aws-sdk version range
-  - Change `@aws-sdk/client-s3` from `3.454.0` to `^3.1014.0` in apps/app/package.json
-  - Change `@aws-sdk/s3-request-presigner` from `3.454.0` to `^3.1014.0`
-  - Update the misleading `"@aws-skd/*"` comment to reflect the actual reason or remove it
-  - Run `pnpm install` and verify build with `turbo run build --filter @growi/app`
-  - Run `turbo run test --filter @growi/app` to confirm no regressions
-  - _Requirements: 1.3, 4.1, 4.2, 4.4_
-
-- [x] 2.2 (P) Upgrade string-width in @growi/editor
-  - Update `string-width` from `=4.2.2` to `^7.0.0` in packages/editor/package.json
-  - Verify @growi/editor builds successfully (Vite, ESM context)
-  - Run `turbo run build --filter @growi/app` to confirm downstream build passes
-  - Run `turbo run test --filter @growi/app` to confirm no regressions
-  - Remove the `string-width` comment from apps/app/package.json `// comments for dependencies`
-  - _Requirements: 2.1, 2.3, 4.1, 4.2, 4.4_
-
-- [x] 3. Upgrade bootstrap to ^5.3.8
-  - Change `bootstrap` from `=5.3.2` to `^5.3.8` in apps/app/package.json and all other packages
-  - Run `pnpm install` to resolve the new version
-  - Run `pnpm run pre:styles-commons` and `pnpm run pre:styles-components` to verify SCSS compilation
-  - Run `turbo run build --filter @growi/app` to confirm Turbopack build passes
-  - Run `turbo run lint --filter @growi/app` to check for type or lint errors
-  - Run `turbo run test --filter @growi/app` to confirm no regressions
-  - Visually inspect modal headers if a dev server is available (original bug was modal header layout)
-  - Remove the `bootstrap` comment from `// comments for dependencies`
-  - If build or SCSS fails, revert and document the failure reason
-  - _Requirements: 1.1, 4.1, 4.2, 4.3, 4.4, 4.5_
-
-- [x] 4. Replace escape-string-regexp with native RegExp.escape()
-- [x] 4.1 Migrate all source files from escape-string-regexp to RegExp.escape()
-  - Replace `import escapeStringRegexp from 'escape-string-regexp'` and corresponding calls with `RegExp.escape()` in each file
-  - Files in apps/app/src: page.ts, page/index.ts, page-grant.ts, users.js, obsolete-page.js, openai.ts (6 files)
-  - Files in packages: core/src/utils/page-path-utils (2 files), remark-lsx/src/server/routes/list-pages/index.ts (1 file)
-  - Ensure each replacement preserves the exact same escaping behavior
-  - _Requirements: 4.1_
-
-- [x] 4.2 Remove escape-string-regexp dependency and verify
-  - Remove `escape-string-regexp` from apps/app/package.json dependencies
-  - Remove from packages/core and packages/remark-lsx package.json if listed
-  - Remove the `escape-string-regexp` comment from `// comments for dependencies`
-  - Remove `escape-string-regexp` entry from `transpilePackages` in next.config.ts
-  - Run `pnpm install` to update lockfile
-  - Run `turbo run build --filter @growi/app` to verify build
-  - Run `turbo run lint --filter @growi/app` to verify no type errors
-  - Run `turbo run test --filter @growi/app` to verify no regressions
-  - If RegExp.escape() has TypeScript issues, add type declaration or adjust lib config
-  - _Requirements: 2.1, 2.2, 4.1, 4.2, 4.3, 4.4, 4.5_
-
-- [x] 5. Upgrade next-themes to ^0.4.x
-- [x] 5.1 Update next-themes and adapt consuming code
-  - Change `next-themes` from `^0.2.1` to `^0.4.6` in apps/app/package.json
-  - Apply required API migration changes across the 12 consuming files identified in design
-  - Pay attention to any renamed exports, changed hook signatures, or provider prop changes
-  - Ensure `useTheme()` and `ThemeProvider` usage is compatible with v0.4.x API
-  - _Requirements: 1.2, 4.1_
-
-- [x] 5.2 Verify next-themes upgrade
-  - Run `turbo run build --filter @growi/app` to confirm build passes
-  - Run `turbo run lint --filter @growi/app` to check for type errors (original pinning was about types)
-  - Run `turbo run test --filter @growi/app` to confirm no regressions
-  - Remove the `next-themes` comment from `// comments for dependencies`
-  - If build or type errors occur, investigate whether the issue is the same as #122 or a new problem
-  - If upgrade fails, revert and document the reason; keep the pin with an updated comment
-  - _Requirements: 4.2, 4.3, 4.4, 4.5, 4.6_
-
-- [x] 6. Finalize audit documentation and comment blocks
-  - Verify `// comments for dependencies` block contains only packages that remain pinned (@keycloak if unchanged)
-  - Verify `// comments for defDependencies` block is accurate (handsontable entries unchanged)
-  - Update comment text to reflect current reasons where applicable
-  - Produce a final summary table in research.md documenting: package name, previous version, new version or "unchanged", and rationale
-  - Confirm all requirements are satisfied by reviewing the checklist against actual changes made
-  - _Requirements: 3.1, 3.2, 4.6, 5.1, 5.2, 5.3_