skillhub/docs/prds/skill-file-browser-sidebar-v1.0-prd.md
XiaoSeS ee33505b7c feat: File Browser Sidebar with Preview, Security Audit UI, and Syntax Highlighting (#145)
* feat(security): extend scanner config with full analyzer options

Integrate skill-scanner's 8 analysis engines and policy configuration
into SkillHub's config system. Operators can now control behavioral,
LLM, Meta, AI Defense, VirusTotal, and trigger analyzers via
application.yml or environment variables.

Changes:
- Add Analyzers and Policy nested classes to SkillScannerProperties
- Create ScanOptions record to encapsulate analyzer flags
- Update SkillScannerService to pass options in /scan body and /scan-upload query params
- Wire ScanOptions through SkillScannerConfig and SkillScannerAdapter
- Extend application.yml with full scanner config block and env var overrides
- Update all tests to verify new configuration flow

All tests pass.

* feat(security): add domain model and integrate scan into publish flow

Add SCANNING/SCAN_FAILED status to SkillVersionStatus. Introduce
SecurityScanService, SecurityScanner port, ScanTask, SecurityAudit
and related domain types. Wire scan trigger into SkillPublishService
so non-auto-publish versions enter scanning when scanner is enabled,
falling back to review task creation when disabled.

* feat(security): add infra layer for scanner HTTP client and adapters

Add WebClient-based HttpClient abstraction with WebClientHttpClient
implementation. Add SkillScannerApiResponse record, SecurityScanException,
and SecurityAuditJpaRepository. Add webflux and test dependencies to
infra module.

* feat(security): add Redis stream consumers, audit API, and DB migration

Add AbstractStreamConsumer base class, ScanTaskConsumer for processing
scan results from Redis stream, and RedisScanTaskProducer. Add
RedisStreamConfig for stream/group initialization. Add SecurityAudit
REST controller and DTO. Add V35 Flyway migration for security_audits
table.

* feat(security): add scanner config to application profiles

Add scanner enabled flag to application-local.yml and
application-test.yml. Enable behavioral analyzer by default
in application.yml.

* feat(deploy): add skill-scanner to docker-compose and k8s manifests

Add skill-scanner service to docker-compose.yml with health check.
Add scanner k8s deployment, service, and configmap entries. Wire
scanner env vars into Makefile dev-all flow. Add verify-scanner.sh
script for post-deploy validation.

* docs(security): add scanner documentation suite

Add scanner docs: configuration guide, failure impact analysis,
monitoring guide, improvement recommendations, custom rules guide,
and skill-vetter rules conversion example. Update deployment docs
with scanner section. Add security-scanning overview and PRD.

* feat(security): add skill-vetter custom rule examples

Add example Regex and YARA rules derived from skill-vetter RED FLAGS
in scanner/examples/vetter-rules/. Includes 7 Regex rules
(signatures-append.yaml) and 3 YARA rules (skillhub_vetter.yara)
covering agent memory theft, IP-based exfiltration, and browser
data theft detection.

* feat(security): add scanner Docker build context

Add Dockerfile for cisco-ai-skill-scanner container and
.env.example with LLM configuration placeholders.

* fix(security): align Finding mapping with scanner API response schema

SkillScannerApiResponse.Finding used incorrect field names (message,
location.file, location.line, code_snippet) that did not match the
scanner's actual JSON output (description, file_path, line_number,
snippet), causing all four fields to deserialize as null.

Flatten Finding to match scanner API: remove nested Location, rename
fields to description/file_path/line_number/snippet. Add skill_name
and timestamp to SkillScannerApiResponse. Extend SecurityFinding with
remediation, analyzer, and metadata fields to capture LLM analyzer
output. Retain 8-arg compact constructor for backward compatibility.

* chore(security): add debug logging to scanner response mapping

Log raw scanner API response and mapped SecurityFinding fields
side-by-side to help verify data consistency between scanner
output and database records.

* feat(security): add multi-scanner support and soft delete for security audits

- Add ScannerType enum for type-safe scanner identification
- Update V35 migration to support multiple scanners and soft delete
- Remove CASCADE delete, use code-level soft delete (deleted_at)
- Add repository methods for querying latest audit by scanner type
- Update SecurityScanService to handle scanner type parameter
- Integrate soft delete in SkillHardDeleteService
- Update all tests to use ScannerType enum

This enables multiple scanner integrations (skill-scanner, future LLM/compliance scanners)
and preserves complete audit history through soft deletion.

* feat(security): add security audit UI to review detail and skill detail pages

Display security scan results on the review detail page (full audit
section with collapsible findings) and the skill detail sidebar (compact
summary with dialog for details).  Handles empty/404 gracefully by
returning null, avoids loading shimmer flicker, and separates lifecycle
action buttons with a visual divider.

* docs(security): add security audit UI PRD

* docs(prd): add related documents section to file browser sidebar PRD

* feat(skill): add file tree builder utility

Implement buildFileTree function to convert flat SkillFile[] into hierarchical tree structure.
- Nodes sorted alphabetically by path
- Support for nested directories
- Each node includes depth, type, and path information
- Includes comprehensive test coverage

* feat(skill): add file type detection utilities

Implement utilities for file type detection and preview capability checks:
- isPreviewable: checks if file can be previewed based on extension and size
- canPreviewFile: provides detailed reason when file cannot be previewed
- getFileTypeLabel: returns human-readable file type labels
- getFileIcon: maps file types to appropriate Lucide icons
- Supports 1MB max file size limit
- Comprehensive test coverage for all functions

* feat(skill): add file tree node component

Implement recursive FileTreeNodeComponent with:
- Expand/collapse functionality for directories
- File and directory icons from Lucide React
- Hover effects showing file sizes
- Proper indentation based on depth
- Support for nested directory structures

* refactor(skill): upgrade file tree to hierarchical structure

Replace flat file list with tree structure:
- Use buildFileTree to convert flat files into hierarchy
- Integrate FileTreeNodeComponent for rendering
- Update onFileClick to accept FileTreeNode instead of SkillFile
- Add file count badge in header
- Root-level directories expanded by default

* feat(skill): add file preview dialog component

Implement FilePreviewDialog with:
- Markdown rendering via existing MarkdownRenderer
- Plain text/code display with monospace font
- Non-previewable file message with download button
- Copy-to-clipboard and download actions in header
- File path display in footer
- Loading and error states

* feat(i18n): add file tree and preview translations

Add Chinese and English translations for:
- File browser title
- Preview error messages (load failure, too large, binary, unsupported)
- Download file button

* feat(skill): integrate file preview into skill detail page

- Add useSkillFile hook for fetching arbitrary file content
- Add file preview state, click handler, and download handler
- Pass onFileClick to FileTree for opening preview dialog
- Add FilePreviewDialog to skill detail page

* feat(review): add file reading API endpoint

Add GET /api/v1/reviews/{id}/file?path=... for reading single files
from the review-bound skill version:
- ReviewController: new endpoint with path traversal validation
- GovernanceWorkflowAppService: route method for review file access
- ReviewSkillDetailAppService: authorization and delegation
- SkillQueryService: getFileContentByVersionId for direct version access

* feat(review): integrate file preview into review detail

- Add useReviewFile hook for fetching review file content
- Add file preview state and handlers to ReviewSkillDetailSection
- Pass reviewId prop for API calls
- Add FilePreviewDialog to review detail expanded section
- Update review-detail.tsx to pass taskId as reviewId

* fix(test): update test mocks for file preview hooks

- Add useSkillFile mock to skill-detail.test.tsx
- Add useQuery mock to @tanstack/react-query mock
- Add useReviewFile mock to review-skill-detail-section.test.tsx
- Fix SkillFile test fixtures to include all required properties
- Remove unused imports in test and component files

* fix(skill): use DomainBadRequestException for version not found

Replace DomainNotFoundException with DomainBadRequestException in
getFileContentByVersionId to match existing patterns and imports.

* feat(skill): add file tree sidebar with file sizes

- Move file tree to right sidebar for persistent visibility
- Display file sizes always visible (not just on hover)
- Keep Files tab showing the same tree structure
- Add scrollable container with max-height for long file lists

* fix(skill): improve file tree sidebar UI and UX

- Remove redundant title from file tree sidebar
- Adjust scrollbar placement with proper flex layout
- Sort folders first, then files (both alphabetically)
- Collapse all folders by default for cleaner initial view
- Increase dialog width to max-w-5xl and height to 90vh
- Remove duplicate close button (X icon)
- Add hover effects to action buttons
- Use flexbox for proper content scrolling
- Allow .pyc files in backend configuration

Fixes:
1. File tree sidebar now has cleaner layout without title
2. Scrollbar properly contained within card
3. Folders appear before files in tree
4. All folders collapsed by default
5. Preview dialog wider and more usable
6. Single close method (ESC or click outside)
7. Action buttons have visual feedback on hover

* fix(skill): refine file tree sidebar and preview dialog

1. Default all folders to collapsed state
2. File tree sidebar now uses Card+bare pattern matching SecurityAuditSummary
   - Scrollbar inside the card content area instead of wrapping the tree
   - Consistent padding and header layout with other sidebar cards
3. Preview dialog close button fixed:
   - Hide DialogContent's built-in close button via [&>button]:hidden
   - Add X button in the header row, same level as copy/download
   - All action buttons share consistent hover animation (opacity transition)
4. Sort directories before files at every tree level
5. Update tests for new directory-first sort order

* feat(skill): collapsible file browser, wider dialog, button animations

1. File browser sidebar now supports expand/collapse toggle
   - Click the header row to toggle visibility
   - ChevronUp/Down icon indicates state
   - Default expanded on page load

2. File preview dialog widened to 72rem (was 5xl/64rem)
   - Uses w-[min(calc(100vw-2rem),72rem)] for responsive max

3. Header action buttons now have micro-interactions:
   - Copy/Download: scale up on hover, scale down on click
   - Close (X): rotates 90° on hover with destructive tint
   - All buttons: opacity 60→100 transition on hover

* feat(skill): chevron animation, button effects, download path hint, review sidebar

1. File browser chevron: single ChevronDown with rotate-180 CSS transition
   instead of swapping two icons — smooth 200ms rotation animation

2. Preview dialog action button animations:
   - Copy icon: active:scale-125 feedback on click
   - Download icon: hover:translate-y-0.5 subtle downward motion
   - Close icon: hover:rotate-90 with destructive tint (unchanged)

3. Download tooltip now shows full file path:
   "下载 src/prompts/system.md" instead of generic "下载文件"
   - New i18n keys: filePreview.downloadHint, filePreview.copy, filePreview.close

4. Review detail page now has a sidebar file browser:
   - Two-column layout (main content + lg:w-80 sidebar)
   - File tree sourced from reviewSkillDetail.files (active review version)
   - Collapsible with same chevron animation as skill detail page
   - Shows active version badge below file tree
   - File preview uses review file API (/reviews/{id}/file?path=...)
   - Test mocks updated for new useReviewFile dependency

* fix(skill): download shows filename, copy rotates with success toast

1. Download button tooltip/text now shows actual filename:
   "下载 README.md" instead of generic path
   - i18n key changed from {{path}} to {{name}}

2. Copy button animation reworked to rotation:
   - idle: hover:rotate-180 on the Copy icon
   - click: animate-spin during clipboard write
   - done: swap to green Check icon for 1.5s, then reset

3. Copy success toast notification:
   - Shows "已复制到剪贴板" / "Copied to clipboard" via toast.success
   - New i18n key: filePreview.copySuccess

* fix(skill): set download attribute so browser saves with original filename

The <a> element was missing the download attribute, causing the browser
to derive the filename from the URL path segment (/file?path=...) which
always resolved to "file". Now explicitly sets link.download = node.name
so the saved file uses the original name (e.g. README.md, config.json).

Applied to all three download handlers:
- skill-detail.tsx (skill version file)
- review-detail.tsx (review sidebar file)
- review-skill-detail-section.tsx (review expanded section file)

* feat(skill): add icons to all sidebar card headers

Add Lucide icons to each sidebar section for visual consistency
with the existing SecurityAuditSummary (Shield) and file browser (Folder):

- Terminal: Install command
- Clock: Pending review (amber-colored to match card theme)
- RefreshCw: Lifecycle management
- Tag: Label management (in SkillLabelPanel component)
- ArrowUpCircle: Promotion
- ShieldCheck: Governance

All icons use the same pattern: w-4 h-4 text-muted-foreground
placed inside a flex row with gap-2 before the section title.

* fix(skill): allow owners to preview all version statuses

When a skill has only a REJECTED version, the detail page crashed with
400 "版本未发布" because assertPreviewAccessible() only allowed PUBLISHED
and PENDING_REVIEW(owner). The frontend fallback to versions[0] would
pick the REJECTED version and fail all file/readme queries.

Backend changes:
- assertPreviewAccessible(): now allows owners and namespace admins to
  preview ANY version status (DRAFT, REJECTED, YANKED, SCANNING, etc.)
  via canManageRestrictedSkill() check. Also passes userNsRoles so
  namespace admin role is respected, not just owner.
- resolveOwnerPendingPreview(): expanded from PENDING_REVIEW-only to
  include all non-published, non-yanked statuses so headlineVersion
  resolves correctly for owners with REJECTED/DRAFT/SCANNING versions.

Frontend changes:
- isOwnerPreviewResolution(): relaxed from checking PENDING_REVIEW
  specifically to checking any non-PUBLISHED status, matching the
  backend's broader projection.

Fixes: owner viewing skill with only REJECTED version → 400 error
Also fixes: DRAFT-only, SCANNING-only, SCAN_FAILED-only scenarios

* docs(requirements): add comprehensive requirements for file preview syntax highlighting

Generated complete documentation suite including:
- Core PRD (clarity score: 95/100)
- Constraints specification (8 business rules)
- Impact analysis (8 risks identified)
- Acceptance cases (25 test cases: 10 positive, 5 error, 7 boundary, 3 security)
- Test plan (100% coverage)

Mode: Quick (3 clarification rounds)
Complexity: Simple (3.5 days estimated)

* feat(skill): add syntax highlighting for code file preview

Implement syntax highlighting for code files in the file preview dialog:
- Add CodeRenderer component using lowlight (highlight.js wrapper via rehype-highlight)
- Add getLanguageForHighlight() to map file extensions to highlight.js languages
- Support 20+ languages: Python, JS/TS, Java, Go, Rust, C/C++, Ruby, PHP, Shell, JSON, YAML, XML, etc.
- Apply 500KB threshold for syntax highlighting (larger files show plain text)
- Maintain visual consistency with Markdown code blocks
- Auto-adapt to light/dark theme using existing CSS variables
- Add lowlight as direct dependency to enable programmatic syntax highlighting

Implements solution 1 from PRD (reuse rehype-highlight infrastructure).

* fix(security): resolve security audit FK constraint and stale query issues

Backend:
- Add hardDeleteByVersionId to physically remove audit records before
  deleting skill versions (fixes FK constraint violation on hard delete)
- Add softDeleteByVersionId calls in SkillGovernanceService and
  SkillPublishService version deletion paths
- Add V36 migration to convert security_audit TIMESTAMP columns to
  TIMESTAMPTZ matching project convention
- Update tests to verify audit cleanup in all deletion flows

Frontend:
- Prevent stale API calls after skill deletion by gating all query
  hooks with a skillDeleted flag that disables them immediately
- Move cache cleanup from useDeleteSkill onSuccess to the handler
  to avoid refetching while the component is still mounted

* fix(skill): handle SCANNING and SCAN_FAILED statuses across all pages

Backend:
- Include SCANNING/SCAN_FAILED in version listing filters so owners
  can see versions being scanned
- Add explicit lifecycle sort priority for scanner statuses
- Allow deletion of SCAN_FAILED versions alongside DRAFT and REJECTED

Frontend:
- Add i18n labels and CSS classes for SCANNING/SCAN_FAILED in my-skills
- Add localized version status labels in skill-detail version list
- Hide archive button when no published version exists (my-skills and
  skill-detail)
- Allow deleting SCAN_FAILED versions from skill-detail

* gitignore
2026-03-23 14:38:47 +08:00

13 KiB
Raw Permalink Blame History

技能详情与审核页文件浏览侧边栏 - 产品需求文档 (PRD)

需求说明

背景

  • 当前技能详情页 space/global/skill-writer 与审核详情区块都提供“概览 / 文件 / 版本”三个 Tab但文件区域仅展示平铺文件列表无法在页面内浏览目录层级或直接查看文件内容。
  • 技能详情页已经具备按路径读取单个文件内容的能力,可用于 README 加载;审核详情页目前仅返回 filesdocumentationPathdocumentationContent,还不具备按任意文件路径读取正文的能力。
  • 用户需要在不下载整个 zip 包的前提下,快速查看 skill 包含的目录结构与具体文件内容,提升详情浏览和审核判断效率。

业务问题

  • 平铺文件列表无法反映目录层级,用户难以理解 skill 包结构。
  • 审核人员在审核页中无法点开任意文件验证实现内容,只能依赖 README 或下载压缩包离线查看。
  • 现有三个 Tab 的主体内容已经承担不同职责若继续把文件浏览塞入当前“文件”Tab会使“概览”与“版本”场景下的跨文件查看成本偏高。

目标用户

  • 浏览技能详情的普通用户
  • 管理技能的作者 / 命名空间成员
  • 在审核中心查看技能内容的审核人员与管理员

价值主张

  • 用统一的侧边文件浏览体验取代当前平铺文件列表,降低理解 skill 包结构的成本。
  • 在技能详情页和审核页提供一致的文件预览能力,减少下载操作和上下文切换。
  • 保持现有三个 Tab 的主语义不变,同时让用户在任意 Tab 下都能快速查看文件内容。

功能概述

核心功能

  1. 在技能详情页与审核详情页中新增常驻文件浏览侧边栏。
  2. 将现有平铺 files 列表重构为目录树,支持文件夹展开 / 合并。
  3. 点击文件节点后,通过弹窗预览文件内容。
  4. 支持 Markdown 文档渲染、常见文本文件源码预览,以及大文件 / 不支持文件类型的不可预览提示。
  5. 对不可预览文件提供下载入口。
  6. 桌面端使用右侧侧边栏布局,移动端将文件浏览区域下沉到主内容区域下方。

本次范围

  • 技能详情页:三个 Tab 下都显示同一份基于当前主版本的文件浏览侧边栏。
  • 审核详情页:三个 Tab 下都显示文件浏览侧边栏,并支持点击任意文件预览。
  • 文件树默认展开第一层目录,其余目录按需展开。
  • 侧边栏需要显示文件类型或文件大小等辅助信息。
  • 点击文件后使用弹窗预览,不切换当前 Tab。

明确不包含

  • 侧边栏内置文件名搜索 / 路径过滤。
  • 技能详情页中独立切换文件浏览版本。
  • 审核页中的版本维度切换浏览权限设计与交互实现。
  • 图片、音视频、富二进制文件的内联预览。
  • 超大文件截断预览。

后续可扩展方向

  • 按版本浏览文件树与文件预览,并结合权限控制设计访问策略。
  • 侧边栏搜索过滤、最近打开文件、选中文件高亮等增强交互。
  • 对 JSON / YAML / TS / JS 等文本文件提供更完整的语法高亮能力。
  • 超大文本文件受控截断预览,基于服务端预览接口返回结构化元数据。

详细需求

用户交互流程

技能详情页

  1. 用户进入技能详情页,默认看到“概览 / 文件 / 版本”三个 Tab。
  2. 无论当前停留在哪个 Tab页面都显示文件浏览侧边栏。
  3. 侧边栏展示基于当前主版本的目录树,第一层目录默认展开。
  4. 用户点击文件夹节点,可展开或收起该目录。
  5. 用户点击文件节点,打开文件预览弹窗。
  6. 若文件是 Markdown则按文档样式渲染。
  7. 若文件是常见文本文件,则按源码块样式显示。
  8. 若文件为二进制、类型不支持或文件过大,则弹窗展示“不可预览”提示,并提供文件下载入口。

审核详情页

  1. 审核人员展开审核详情区块。
  2. 在“概览 / 文件 / 版本”任一 Tab 下,都能看到文件浏览侧边栏。
  3. 审核人员点击任意文件后,打开与技能详情页一致的文件预览弹窗。
  4. 若审核页现有接口无法提供目标文件正文,则需通过新增或扩展接口补齐能力。

页面布局要求

桌面端

  • 主内容区域与文件浏览侧边栏形成双栏布局。
  • 三个 Tab 的主内容保持原有语义:
    • 概览README / 文档主体。
    • 文件:文件树本身可作为主内容补充或说明区域,但不再是唯一的文件入口。
    • 版本:版本列表与生命周期信息。
  • 文件预览使用独立弹窗,避免改变主内容布局或跳转当前 Tab。

移动端

  • 不保留强制双栏。
  • 文件浏览区域下沉到主内容区域之后,仍在三个 Tab 下可见。
  • 文件预览弹窗优先采用接近全屏的移动端弹层体验。
  • 需避免任何横向滚动作为主要交互方式。

文件树行为

  • 输入数据源为现有平铺 SkillFile[] 列表,前端负责构建树形节点。
  • 节点类型分为目录节点与文件节点。
  • 目录节点支持展开 / 收起。
  • 文件节点支持点击打开预览弹窗。
  • 侧边栏中显示文件类型或文件大小信息,帮助用户判断文件性质。
  • 第一层目录默认展开;更深层目录默认折叠。

文件预览行为

  • Markdown 文件:复用现有 Markdown 渲染能力。
  • 文本文件:优先以源码 / 纯文本方式渲染,保留可滚动阅读体验。
  • 二进制文件:展示“当前文件类型暂不支持预览”。
  • 超大文件:展示“文件过大,暂不支持预览”,并给出下载入口。
  • 所有不可预览文件都必须提供可触达的下载能力。
  • 预览弹窗需要显示当前文件路径,便于用户确认查看对象。

数据与接口需求

技能详情页

  • 继续复用当前按路径读取文件正文的能力。
  • 需要将当前 README 专用的单文件读取能力抽象成“任意文件读取”查询逻辑,供预览弹窗复用。

审核详情页

  • 需要补齐按路径读取任意文件正文的能力。
  • 可接受的实现方式:
    1. 新增审核场景专用文件读取接口。
    2. 扩展当前 review detail 数据获取链路,增加任意文件按路径读取能力。
  • 目标是让审核页的文件预览能力与技能详情页对齐,而不是仅支持 README。

开源组件策略

  • 实现前需优先评估成熟开源组件是否能满足文件树或代码预览需求。
  • 评估前提:样式必须能与当前 React + Tailwind + 现有 UI 体系自然融合。
  • 若第三方组件在样式一致性、包体积、移动端适配或维护成本上不满足要求,则回退为轻量自研方案。
  • 当前项目已具备 react-markdownrehype-highlight 与现有 Dialog 基础能力,应优先复用已有依赖,避免引入风格冲突较大的重型组件。

设计决策

交互决策

  • 采用“常驻文件导航 + 弹窗预览”模式,而不是切换主内容 Tab 或在侧边栏内直接阅读正文。
  • 理由:
    • 保持现有三个 Tab 的语义稳定。
    • 允许用户在“概览”或“版本”上下文中快速查看文件。
    • 更适合移动端,将阅读行为独立到弹窗层处理。

响应式决策

  • 桌面端为右侧常驻侧边栏。
  • 移动端为主内容下方文件浏览区 + 接近全屏的预览弹层。
  • 需保证 320 / 375 / 414 / 768 / 1024 / 1440 等常见宽度下无异常横向滚动。

样式与可用性决策

  • 延续当前页面的数据密集型管理界面风格,不引入与现有设计系统冲突的第三方视觉语言。
  • 文件树节点、弹窗关闭按钮、下载按钮需具备清晰 hover / focus 状态。
  • 交互动效应控制在 150-300ms 范围内,并尊重 prefers-reduced-motion
  • 移动端点击目标需满足最小可触达尺寸。

技术约束

前端约束

  • 必须兼容现有技能详情页与审核详情页结构,不破坏当前三个 Tab 的主内容与既有操作。
  • 复用现有 Dialog、MarkdownRenderer、i18n、TanStack Query 模式。
  • 文件树由前端从平铺文件列表构建,不要求后端返回嵌套目录结构。
  • 不允许因为引入新组件导致现有样式体系明显漂移。

后端约束

  • 本期允许为审核页补充新接口或扩展现有返回结构,但应避免引入数据库 schema 变化。
  • 文件读取能力应限定在当前审核上下文可访问的 skill 版本上,不扩大权限边界。
  • 对超大文件 / 不支持预览类型应能返回明确错误或元信息,便于前端区分不可预览原因。

性能约束

  • 打开文件树不应阻塞页面初次渲染。
  • 文件预览按需加载,不能一次性拉取所有文件正文。
  • 目录树展开 / 收起应保持即时响应,不因大规模重渲染造成明显卡顿。

安全约束

  • 继续沿用现有技能详情页和审核页的鉴权边界。
  • 审核页新增文件正文读取能力时,必须确保仅审核相关角色可访问对应资源。
  • 不可通过构造任意路径越权读取 skill 包之外的内容。

国际化约束

  • 中英文都需补充文件浏览、预览、不可预览、大文件提示、下载操作等文案。

风险评估

技术风险

  1. 审核页缺少任意文件正文读取能力,若后端接口设计不清晰,可能导致前后端联调返工。
  2. 第三方文件树 / 代码查看组件可能与现有 Tailwind 风格不匹配,带来样式整合成本。
  3. 文件类型判断与大文件判定策略若不统一,可能导致详情页与审核页行为不一致。

交互风险

  1. 桌面端双栏与移动端单栏切换如果布局边界控制不好,容易出现横向滚动或内容拥挤。
  2. 弹窗预览若对长文本处理不当,可能造成滚动区域难用或阅读效率差。

缓解措施

  • 优先复用现有 Markdown、Dialog 与查询模式,减少引入面。
  • 将“按路径读取正文”的能力抽象为共享模型,详情页和审核页统一使用。
  • 先定义统一的“可预览 / 不可预览 / 可下载”判定规则,再进入实现。
  • 将第三方组件引入作为可选路径,而非前置依赖。

验收标准

功能验收

  • 技能详情页三个 Tab 下均能看到文件浏览侧边栏。
  • 审核详情页三个 Tab 下均能看到文件浏览侧边栏。
  • 平铺文件列表能正确转换为目录树,且支持文件夹展开 / 收起。
  • 点击文件节点后能打开预览弹窗。
  • Markdown 文件能正确渲染。
  • 常见文本文件能以源码 / 纯文本形式展示。
  • 二进制文件或超大文件会显示不可预览提示。
  • 不可预览文件提供下载入口。
  • 审核页支持点击任意文件并预览,不局限于 README。

质量验收

  • 桌面端采用右侧侧边栏布局,移动端文件浏览区下沉到主内容下方。
  • 页面在常见断点下无异常横向滚动。
  • 不影响现有“概览 / 文件 / 版本”Tab 的既有内容与操作。
  • 新增文案完成中英文国际化覆盖。

执行阶段

Phase 1: 共享模型与交互方案落地

  • 明确文件树节点模型、可预览类型规则、不可预览提示规则。
  • 评估是否存在可复用的开源文件树 / 文本预览能力,并完成选型结论。

Phase 2: 技能详情页集成

  • 抽象任意文件读取查询逻辑。
  • 将技能详情页平铺文件列表升级为目录树侧边栏。
  • 接入弹窗预览与下载能力。

Phase 3: 审核页能力补齐

  • 为审核页补充任意文件正文读取接口或数据链路。
  • 在审核详情区块接入共享文件树与预览弹窗。

Phase 4: 回归与体验完善

  • 补充中英文文案。
  • 验证桌面端 / 移动端布局、弹窗滚动、不可预览场景。
  • 补充回归测试,确保现有 Tab 内容和审核流程不受影响。

非本期需求记录

  • 文件浏览版本切换需要单独设计权限边界、交互入口和不影响现有功能的约束,本期仅记录,不实现。

关联文档

需求文档

执行计划

技术参考

  • 现有组件:
    • web/src/features/skill/file-tree.tsx - 当前平铺文件列表实现
    • web/src/features/skill/markdown-renderer.tsx - Markdown 渲染器
    • web/src/shared/ui/dialog.tsx - 弹窗组件
  • 现有 API
    • GET /api/v1/skills/{namespace}/{slug}/versions/{version}/file?path=... - 技能文件读取接口
    • GET /api/v1/reviews/{id} - 审核详情接口(需扩展)