Skip to content

rss feed support - #15

Merged
newbe36524 merged 1 commit into
mainfrom
rsshub
Feb 10, 2026
Merged

newbe36524 merged 1 commit into
mainfrom
rsshub

Conversation

@newbe36524

@newbe36524 newbe36524 commented Feb 10, 2026 •

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features
    • Added official blog RSS feed integration displaying the latest blog posts within the app
    • Automatic feed refresh every 24 hours with manual refresh capability
    • Offline caching for continuous access to blog posts
    • Multi-language support for the blog feed interface (English and Chinese)

@coderabbitai

coderabbitai Bot commented Feb 10, 2026 •

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This PR implements an official blog RSS feed integration for Hagicode Desktop, adding a singleton RSSFeedManager for fetching and caching RSS content, Redux state management for the renderer, a BlogFeedCard UI component, IPC handlers bridging main and renderer processes, type definitions, and internationalization support for displaying blog posts in the app.

Changes

Cohort / File(s) Summary
Design & Planning
openspec/changes/archive/2025-02-10-official-blog-rss-feed-integration/proposal.md, openspec/changes/archive/2025-02-10-official-blog-rss-feed-integration/tasks.md
Comprehensive design proposal documenting architecture, data structures, IPC channels, UI flow, and implementation plan with phase-based tasks and acceptance criteria.
Type Definitions
src/main/types/rss-types.ts
Introduces three interfaces: RSSFeedItem (article metadata), RSSFeedCache (cached items with timestamp), and RSSFeedConfig (manager configuration).
Main Process
src/main/rss-feed-manager.ts, src/main/main.ts
Adds RSSFeedManager singleton class with fetch, parse, cache, and auto-refresh logic; registers three IPC handlers (rss-get-feed-items, rss-refresh-feed, rss-get-last-update); expands allowed domains for external links.
IPC & Preload Bridge
src/preload/index.ts
Exposes new rss API namespace (getFeedItems, refreshFeed, getLastUpdate) under electronAPI for renderer access to main process RSS functionality.
Renderer State Management
src/renderer/store/slices/rssFeedSlice.ts, src/renderer/store/sagas/rssFeedSaga.ts, src/renderer/store/index.ts
Implements Redux slice with items, loading, error, and lastUpdate state; defines action creators and sagas for fetch, refresh, and update operations; integrates into root store.
UI Components & Integration
src/renderer/components/BlogFeedCard.tsx, src/renderer/components/SystemManagementView.tsx
Creates BlogFeedCard component with feed display, refresh button, error/loading/empty states, HTML stripping, date formatting, and animations; integrates into SystemManagementView.
Internationalization
src/renderer/i18n/locales/en-US/components.json, src/renderer/i18n/locales/zh-CN/components.json
Adds blogFeed localization strings for both English and Chinese, including title, refresh, loading, error, noArticles, and lastUpdate labels.
Dependencies
package.json
Adds rss-parser (^3.13.0) as runtime and dev dependency; updates dev script to remove npm run predev call.

Sequence Diagrams

sequenceDiagram
    participant Renderer as Renderer Process
    participant IPC as IPC Channel
    participant Main as Main Process
    participant Fetch as HTTP/Axios
    participant Cache as Electron Store
    participant Parser as RSS Parser

    Renderer->>IPC: rss-get-feed-items()
    IPC->>Main: Receive request
    
    alt Cache valid
        Main->>Cache: Read cached items
        Cache-->>Main: Return cached items
    else Cache invalid or missing
        Main->>Fetch: Fetch RSS XML from feed URL
        Fetch-->>Main: RSS XML response
        Main->>Parser: Parse XML
        Parser-->>Main: RSSFeedItem[] objects
        Main->>Cache: Store items + lastUpdate
        Cache-->>Main: Cache stored
    end
    
    Main-->>IPC: Return RSSFeedItem[]
    IPC-->>Renderer: Feed items received
Loading
sequenceDiagram
    participant User as User/UI
    participant Component as BlogFeedCard
    participant Store as Redux Store
    participant Saga as RSS Saga
    participant IPC as IPC/electronAPI
    participant Main as Main Process

    User->>Component: Page mount or refresh click
    Component->>Store: Dispatch fetchFeedItemsAction
    Store->>Saga: Watch FETCH_FEED_ITEMS action
    Saga->>Saga: Set loading = true
    Saga->>IPC: Call electronAPI.rss.getFeedItems()
    IPC->>Main: Invoke 'rss-get-feed-items'
    Main-->>IPC: Return RSSFeedItem[] and lastUpdate
    IPC-->>Saga: Data received
    Saga->>Store: Dispatch setItems, setLoading(false), setLastUpdate
    Store-->>Component: Update state
    Component->>Component: Render feed items, clear loading state
    User-->>Component: View blog posts
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • No directly related PRs found in the search results with strong code-level connections beyond this feature set.

Poem

🐰 A blog feed hops into place,
RSS items fill the space,
Cached and fresh, no delay,
Blog updates every day!
Electrons dance 'cross the process line,
Hagicode's stories now align. ✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The PR title 'rss feed support' is vague and lacks specificity about what aspect of RSS feed functionality is being added or how it integrates with the application. Consider a more descriptive title such as 'Add official blog RSS feed integration to home page' or 'Implement RSS feed manager with caching and auto-refresh' to better convey the scope and purpose of the changes.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch rsshub

Comment @coderabbitai help to get the list of available commands and usage tips.

@newbe36524
newbe36524 merged commit 42226f3 into main Feb 10, 2026
3 of 4 checks passed
@newbe36524
newbe36524 deleted the rsshub branch February 10, 2026 12:04

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🤖 Fix all issues with AI agents
In
`@openspec/changes/archive/2025-02-10-official-blog-rss-feed-integration/proposal.md`:
- Around line 3-60: Update the proposal headings to match the standard template
by replacing or adding the sections: "Why" (move Background & motivation content
here), "What Changes" (move Scope and high-level change list here), "UI Design
Changes" (extract and expand any UI/UX details like
BlogFeedCard/SystemManagementView integration), "Code Flow Changes" (move
Technical Design items like rss-feed-manager.ts, IPC channels, rssFeedSlice/saga
and persistence/refresh logic here), and "Impact" (list rollout, performance,
privacy and maintenance impacts); ensure each section contains the existing
relevant text from Overview/Background/Scope/Technical Design and rename
headings accordingly while keeping the RSS URL, change ID and metadata intact.
- Around line 64-110: The fenced ASCII diagram in proposal.md lacks a language
tag, triggering markdownlint MD040; update the opening fence for the diagram
(the triple-backtick block that begins the ASCII diagram containing "渲染进程
(Renderer)" and the box-drawing characters) to include a language identifier
such as text (e.g., change ``` to ```text) so the fenced code block is properly
annotated.

In
`@openspec/changes/archive/2025-02-10-official-blog-rss-feed-integration/tasks.md`:
- Around line 7-30: The markdown file contains multiple fenced code blocks
without language identifiers (e.g., the task list blocks in
openspec/changes/archive/2025-02-10-official-blog-rss-feed-integration/tasks.md);
update every triple-backtick fence used for the phase/task diagrams and the UI
ASCII art blocks to include a language tag (for these cases use "text" or
"plain") so markdownlint warnings are resolved—ensure you update all occurrences
(including the additional range noted at lines 240-259) by replacing ``` with
```text (or ```plain) at each opening fence and keeping the matching closing
fences unchanged.
- Around line 49-381: Update the checklist items in this tasks.md to mark
completed work as done by changing "- [ ]" to "- [x]" for tasks that have been
fully implemented and verified (e.g., the T1.2, T2.1-T2.3, T3.1-T3.2, T4.1-T4.3,
T5.1-T5.3 entries and their sub-items); ensure you only flip boxes after
confirming implementation and tests, update all instances under
openspec/changes/*/tasks.md, and include a brief commit message like "mark RSS
feature tasks completed" when committing the changes.

In `@package.json`:
- Line 21: The dev script uses the POSIX-only rm -rf which breaks on Windows;
update the "dev" npm script to use a cross-platform deletion tool (e.g., replace
rm -rf dist with rimraf dist or use shx rm -rf dist) and add the corresponding
devDependency (e.g., rimraf) so npm run dev works on Windows, keeping the rest
of the concurrently command and the referenced scripts ("dev:renderer",
"dev:main", "dev:preload") unchanged.

In `@src/renderer/components/BlogFeedCard.tsx`:
- Around line 176-180: The article tile uses a clickable div which is not
keyboard-accessible; update the BlogFeedCard so the interactive container uses a
semantic element (prefer an <a> or <button>) or at minimum adds role, tabIndex
and key event handling; replace the clickable <div> that calls
handleArticleClick(item.link) with a semantic element (e.g., an anchor linking
to item.link or a button that calls handleArticleClick) and ensure focus
styles/hover classes are preserved and Enter/Space key activation is supported
if you choose a non-semantic element; reference the interactive container around
handleArticleClick and the item.link usage when making the change.
🧹 Nitpick comments (1)
src/main/types/rss-types.ts (1)

9-22: Consider sharing RSSFeedItem across main/renderer to avoid drift.
The same interface exists in src/renderer/store/slices/rssFeedSlice.ts; a shared type module would reduce duplication.

Comment on lines +3 to +60
## 概述

在 Hagicode Desktop 应用主页集成 Hagicode 官方博客的 RSS 订阅源,允许用户直接在应用内查看最新的官方动态、技术文章和产品更新公告。

**变更 ID**: `official-blog-rss-feed-integration`
**状态**: ExecutionCompleted
**目标版本**: 待定

## 背景与动机

### 当前状态

Hagicode Desktop 是一个基于 Electron 的跨平台桌面应用,提供 Web 服务管理、包管理等功能。目前主页缺少官方博客内容的展示,用户需要:

- 手动访问外部网站获取 Hagicode 最新动态
- 无法及时了解产品更新和功能发布公告
- 缺少快速访问官方文档和教程资源的入口

### 目标

通过集成官方博客 RSS 订阅源(`https://docs.hagicode.com/blog/rss.xml`),在应用主页提供:
- 最新 5 条博客文章的快速预览
- 自动刷新机制,确保内容及时更新
- 一键跳转至完整文章

## 范围

### 包含内容

1. **主进程 RSS 管理器**
- 创建 `rss-feed-manager.ts` 单例管理器
- 实现从 `https://docs.hagicode.com/blog/rss.xml` 获取和解析 RSS 数据
- 使用 electron-store 持久化缓存 RSS 数据
- 实现每 24 小时自动刷新机制

2. **IPC 通信层**
- `rss-get-feed-items` - 获取 RSS 文章列表
- `rss-refresh-feed` - 手动触发刷新
- `rss-get-last-update` - 获取上次更新时间

3. **渲染进程状态管理**
- 创建 `rssFeedSlice.ts` 管理 RSS 状态
- 创建 `rssFeedSaga.ts` 处理异步操作

4. **UI 组件**
- 创建 `BlogFeedCard.tsx` 展示博客文章列表
- 集成到主页(SystemManagementView.tsx)

5. **国际化支持**
- 中英文翻译文件更新

### 排除内容

- RSS 订阅源配置界面(仅使用固定的官方博客地址)
- 离线模式下的缓存阅读(仅缓存数据用于刷新间隔)
- 博客内容的全文展示(仅摘要和跳转链接)

## 技术设计

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add the standard proposal sections (Why / What Changes / UI Design Changes / Code Flow Changes / Impact).
Please add or rename headings to match the required template; the current structure uses Overview/Background/Scope/Technical Design instead.

Based on learnings: Structure proposal.md with Why, What Changes, UI Design Changes (if applicable), Code Flow Changes (if applicable), and Impact sections.

🤖 Prompt for AI Agents
In
`@openspec/changes/archive/2025-02-10-official-blog-rss-feed-integration/proposal.md`
around lines 3 - 60, Update the proposal headings to match the standard template
by replacing or adding the sections: "Why" (move Background & motivation content
here), "What Changes" (move Scope and high-level change list here), "UI Design
Changes" (extract and expand any UI/UX details like
BlogFeedCard/SystemManagementView integration), "Code Flow Changes" (move
Technical Design items like rss-feed-manager.ts, IPC channels, rssFeedSlice/saga
and persistence/refresh logic here), and "Impact" (list rollout, performance,
privacy and maintenance impacts); ensure each section contains the existing
relevant text from Overview/Background/Scope/Technical Design and rename
headings accordingly while keeping the RSS URL, change ID and metadata intact.

Comment on lines +64 to +110
```
┌─────────────────────────────────────────────────────────────┐
│ 渲染进程 (Renderer) │
├─────────────────────────────────────────────────────────────┤
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ BlogFeedCard │◄────│ rssFeedSlice │ │
│ │ (UI 组件) │ │ (Redux 状态) │ │
│ └─────────────────┘ └─────────────────┘ │
│ ▲ ▲ │
│ │ │ │
│ └───────┬───────────────┘ │
│ │ │
│ ┌────────▼────────┐ │
│ │ rssFeedSaga │ │
│ │ (异步处理) │ │
│ └────────┬────────┘ │
└──────────────────┼───────────────────────────────────────────┘
│ IPC 通信
▼
┌─────────────────────────────────────────────────────────────┐
│ 主进程 (Main) │
├─────────────────────────────────────────────────────────────┤
│ ┌──────────────────────────────────────────────────────┐ │
│ │ rss-feed-manager.ts (单例) │ │
│ │ ┌─────────────────────────────────────────────────┐ │ │
│ │ │ • fetchRSSFeed() - 获取 RSS 数据 │ │ │
│ │ │ • parseRSSXML() - 解析 XML │ │ │
│ │ │ • getCachedFeed() - 获取缓存数据 │ │ │
│ │ │ • refreshFeed() - 刷新 RSS 数据 │ │ │
│ │ │ • startAutoRefresh() - 启动定时刷新 │ │ │
│ │ └─────────────────────────────────────────────────┘ │ │
│ └──────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ electron-store (持久化) │ │
│ │ • rssFeed.items - 文章列表 │ │
│ │ • rssFeed.lastUpdate - 最后更新时间 │ │
│ └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 外部数据源 │
│ https://docs.hagicode.com/blog/rss.xml │
└─────────────────────────────────────────────────────────────┘
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Specify a language for the fenced diagram block.
markdownlint MD040 requires a language on fenced code blocks.

📝 Suggested fix
-```
+```text
┌─────────────────────────────────────────────────────────────┐
│                      渲染进程 (Renderer)                      │
...
└─────────────────────────────────────────────────────────────┘
-```
+```
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
```
┌─────────────────────────────────────────────────────────────┐
│ 渲染进程 (Renderer) │
├─────────────────────────────────────────────────────────────┤
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ BlogFeedCard │◄────│ rssFeedSlice │ │
│ │ (UI 组件) │ │ (Redux 状态) │ │
│ └─────────────────┘ └─────────────────┘ │
│ ▲ ▲ │
│ │ │ │
│ └───────┬───────────────┘ │
│ │ │
│ ┌────────▼────────┐ │
│ │ rssFeedSaga │ │
│ │ (异步处理) │ │
│ └────────┬────────┘ │
└──────────────────┼───────────────────────────────────────────┘
│ IPC 通信
▼
┌─────────────────────────────────────────────────────────────┐
│ 主进程 (Main) │
├─────────────────────────────────────────────────────────────┤
│ ┌──────────────────────────────────────────────────────┐ │
│ │ rss-feed-manager.ts (单例) │ │
│ │ ┌─────────────────────────────────────────────────┐ │ │
│ │ │ • fetchRSSFeed() - 获取 RSS 数据 │ │ │
│ │ │ • parseRSSXML() - 解析 XML │ │ │
│ │ │ • getCachedFeed() - 获取缓存数据 │ │ │
│ │ │ • refreshFeed() - 刷新 RSS 数据 │ │ │
│ │ │ • startAutoRefresh() - 启动定时刷新 │ │ │
│ │ └─────────────────────────────────────────────────┘ │ │
│ └──────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ electron-store (持久化) │ │
│ │ • rssFeed.items - 文章列表 │ │
│ │ • rssFeed.lastUpdate - 最后更新时间 │ │
│ └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 外部数据源 │
│ https://docs.hagicode.com/blog/rss.xml │
└─────────────────────────────────────────────────────────────┘
```
🧰 Tools
🪛 markdownlint-cli2 (0.20.0)

[warning] 64-64: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
In
`@openspec/changes/archive/2025-02-10-official-blog-rss-feed-integration/proposal.md`
around lines 64 - 110, The fenced ASCII diagram in proposal.md lacks a language
tag, triggering markdownlint MD040; update the opening fence for the diagram
(the triple-backtick block that begins the ASCII diagram containing "渲染进程
(Renderer)" and the box-drawing characters) to include a language identifier
such as text (e.g., change ``` to ```text) so the fenced code block is properly
annotated.

Comment on lines +7 to +30
```
Phase 1: 准备工作
├── T1.1 安装 rss-parser 依赖
└── T1.2 定义 TypeScript 类型

Phase 2: 主进程开发
├── T2.1 创建 RSS Feed Manager
├── T2.2 实现 IPC 通道注册
└── T2.3 配置预加载脚本

Phase 3: 渲染进程状态管理
├── T3.1 创建 rssFeedSlice
└── T3.2 创建 rssFeedSaga

Phase 4: UI 组件开发
├── T4.1 创建 BlogFeedCard 组件
├── T4.2 集成到主页
└── T4.3 添加国际化翻译

Phase 5: 测试与验证
├── T5.1 功能测试
├── T5.2 错误处理测试
└── T5.3 国际化验证
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add language identifiers to fenced code blocks.
markdownlint warns when code blocks lack a language tag.

✍️ Suggested fix
-```
+```text
 Phase 1: 准备工作
 ├── T1.1 安装 rss-parser 依赖
 └── T1.2 定义 TypeScript 类型
@@
-```
+```

@@
-```
+```text
 ┌─────────────────────────────────────────┐
 │  📰 Hagicode 博客               [刷新]  │
@@
-```
+```

Also applies to: 240-259

🧰 Tools
🪛 markdownlint-cli2 (0.20.0)

[warning] 7-7: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
In
`@openspec/changes/archive/2025-02-10-official-blog-rss-feed-integration/tasks.md`
around lines 7 - 30, The markdown file contains multiple fenced code blocks
without language identifiers (e.g., the task list blocks in
openspec/changes/archive/2025-02-10-official-blog-rss-feed-integration/tasks.md);
update every triple-backtick fence used for the phase/task diagrams and the UI
ASCII art blocks to include a language tag (for these cases use "text" or
"plain") so markdownlint warnings are resolved—ensure you update all occurrences
(including the additional range noted at lines 240-259) by replacing ``` with
```text (or ```plain) at each opening fence and keeping the matching closing
fences unchanged.

Comment on lines +49 to +381
**验收标准**:
- [ ] `rss-parser` 已添加到 package.json dependencies
- [ ] `npm install` 无错误完成

---

### T1.2 定义 TypeScript 类型

**优先级**: 高
**预计工作量**: 10 分钟
**依赖**: T1.1

**描述**:
定义 RSS 相关的 TypeScript 接口和类型。

**执行步骤**:
1. 创建文件 `src/main/types/rss-types.ts`
2. 定义 `RSSFeedItem` 接口
3. 定义 `RSSFeedCache` 接口

**代码位置**: `src/main/types/rss-types.ts` (新建)

**验收标准**:
- [ ] 类型定义文件已创建
- [ ] 类型包含所有必需字段
- [ ] 类型导出正确

---

## Phase 2: 主进程开发

### T2.1 创建 RSS Feed Manager

**优先级**: 高
**预计工作量**: 60 分钟
**依赖**: T1.2

**描述**:
创建单例模式的 RSS Feed Manager,负责获取、解析和缓存 RSS 数据。

**执行步骤**:
1. 创建 `src/main/rss-feed-manager.ts`
2. 实现单例模式(参考现有管理器如 `web-service-manager.ts`)
3. 实现 `fetchRSSFeed()` 方法 - 使用 axios 获取 RSS 数据
4. 实现 `parseRSSXML()` 方法 - 使用 rss-parser 解析 XML
5. 实现 `getCachedFeed()` 方法 - 从 electron-store 读取缓存
6. 实现 `refreshFeed()` 方法 - 获取并更新缓存
7. 实现 `startAutoRefresh()` 方法 - 设置 24 小时定时刷新
8. 实现 `getLastUpdateTime()` 方法 - 返回最后更新时间

**代码位置**: `src/main/rss-feed-manager.ts` (新建)

**验收标准**:
- [ ] 单例模式正确实现
- [ ] 成功从 `https://docs.hagicode.com/blog/rss.xml` 获取数据
- [ ] RSS XML 正确解析为 `RSSFeedItem[]`
- [ ] 数据正确缓存到 electron-store
- [ ] 自动刷新定时器正确设置

---

### T2.2 实现 IPC 通道注册

**优先级**: 高
**预计工作量**: 30 分钟
**依赖**: T2.1

**描述**:
在主进程注册 RSS 相关的 IPC 处理程序。

**执行步骤**:
1. 编辑 `src/main/index.ts`
2. 导入 `RssFeedManager`
3. 获取管理器实例
4. 注册 `rss-get-feed-items` 处理程序
5. 注册 `rss-refresh-feed` 处理程序
6. 注册 `rss-get-last-update` 处理程序

**代码位置**: `src/main/index.ts` (修改)

**验收标准**:
- [ ] 所有 IPC 通道已注册
- [ ] 通道正确调用管理器方法
- [ ] 错误处理已实现

---

### T2.3 配置预加载脚本

**优先级**: 高
**预计工作量**: 20 分钟
**依赖**: T2.2

**描述**:
在预加载脚本中暴露 RSS API 给渲染进程。

**执行步骤**:
1. 编辑 `src/preload/index.ts`
2. 在 `electronAPI` 对象中添加 RSS 方法
3. 添加类型定义(如需要)

**代码位置**: `src/preload/index.ts` (修改)

**验收标准**:
- [ ] RSS API 已暴露给渲染进程
- [ ] 类型定义正确
- [ ] 预加载脚本编译无错误

---

## Phase 3: 渲染进程状态管理

### T3.1 创建 rssFeedSlice

**优先级**: 高
**预计工作量**: 30 分钟
**依赖**: T2.3

**描述**:
创建 Redux Toolkit slice 管理 RSS 状态。

**执行步骤**:
1. 创建 `src/renderer/store/slices/rssFeedSlice.ts`
2. 定义状态接口:`items`, `loading`, `error`, `lastUpdate`
3. 实现 `setItems` reducer
4. 实现 `setLoading` reducer
5. 实现 `setError` reducer
6. 实现 `setLastUpdate` reducer

**代码位置**: `src/renderer/store/slices/rssFeedSlice.ts` (新建)

**验收标准**:
- [ ] Slice 正确导出
- [ ] Reducers 正确实现
- [ ] Actions 正确导出
- [ ] Slice 已添加到 store 配置

---

### T3.2 创建 rssFeedSaga

**优先级**: 高
**预计工作量**: 40 分钟
**依赖**: T3.1

**描述**:
创建 Redux Saga 处理 RSS 相关的异步操作。

**执行步骤**:
1. 创建 `src/renderer/store/sagas/rssFeedSaga.ts`
2. 实现 `fetchFeedItemsSaga` - 获取文章列表
3. 实现 `refreshFeedSaga` - 刷新 RSS 数据
4. 实现 `fetchLastUpdateSaga` - 获取最后更新时间
5. 注册 saga 监听器

**代码位置**: `src/renderer/store/sagas/rssFeedSaga.ts` (新建)

**验收标准**:
- [ ] Saga 正确监听 actions
- [ ] IPC 调用正确实现
- [ ] 状态更新正确
- [ ] 错误处理已实现
- [ ] Saga 已添加到 root saga

---

## Phase 4: UI 组件开发

### T4.1 创建 BlogFeedCard 组件

**优先级**: 高
**预计工作量**: 60 分钟
**依赖**: T3.2

**描述**:
创建博客文章展示卡片组件。

**执行步骤**:
1. 创建 `src/renderer/components/BlogFeedCard.tsx`
2. 使用 shadcn/ui Card 组件作为容器
3. 实现文章列表渲染(最多 5 条)
4. 实现每条文章的显示:标题、日期、摘要
5. 添加刷新按钮
6. 实现加载状态 UI
7. 实现错误状态 UI
8. 实现点击跳转功能
9. 应用国际化翻译

**代码位置**: `src/renderer/components/BlogFeedCard.tsx` (新建)

**UI 设计参考**:
```
┌─────────────────────────────────────────┐
│ 📰 Hagicode 博客 [刷新] │
├─────────────────────────────────────────┤
│ ◦ 产品发布:Hagicode v2.0 正式发布 │
│ 2025-01-15 │
├─────────────────────────────────────────┤
│ ◦ 教程:如何配置自定义包源 │
│ 2025-01-10 │
├─────────────────────────────────────────┤
│ ◦ 更新日志:版本 v1.9.5 修复内容 │
│ 2025-01-05 │
├─────────────────────────────────────────┤
│ ◦ 技术文章:Electron 应用性能优化实践 │
│ 2024-12-28 │
├─────────────────────────────────────────┤
│ ◦ 公告:服务器维护通知 │
│ 2024-12-20 │
└─────────────────────────────────────────┘
```

**验收标准**:
- [ ] 组件正确渲染
- [ ] 显示最多 5 条文章
- [ ] 加载状态显示正确
- [ ] 错误状态显示正确
- [ ] 刷新按钮功能正常
- [ ] 点击文章正确跳转
- [ ] 国际化文本显示正确

---

### T4.2 集成到主页

**优先级**: 高
**预计工作量**: 15 分钟
**依赖**: T4.1

**描述**:
将 BlogFeedCard 组件集成到应用主页。

**执行步骤**:
1. 编辑 `src/renderer/components/SystemManagementView.tsx`
2. 导入 `BlogFeedCard` 组件
3. 导入 `useAppDispatch` 和 `useAppSelector`
4. 在组件挂载时 dispatch 获取 RSS 数据的 action
5. 在适当位置添加 `BlogFeedCard` 组件

**代码位置**: `src/renderer/components/SystemManagementView.tsx` (修改)

**验收标准**:
- [ ] BlogFeedCard 已添加到主页
- [ ] 组件在挂载时自动加载数据
- [ ] 布局正确,不影响其他组件

---

### T4.3 添加国际化翻译

**优先级**: 中
**预计工作量**: 15 分钟
**依赖**: T4.1

**描述**:
添加中英文翻译支持。

**执行步骤**:
1. 编辑 `src/renderer/i18n/locales/zh-CN/components.json`
2. 添加以下翻译键:
- `blogFeed.title` - "Hagicode 博客"
- `blogFeed.refresh` - "刷新"
- `blogFeed.loading` - "加载中..."
- `blogFeed.error` - "加载失败,请稍后重试"
- `blogFeed.noArticles` - "暂无文章"
- `blogFeed.lastUpdate` - "最后更新:{date}"

3. 编辑 `src/renderer/i18n/locales/en-US/components.json`
4. 添加对应的英文翻译

**代码位置**:
- `src/renderer/i18n/locales/zh-CN/components.json` (修改)
- `src/renderer/i18n/locales/en-US/components.json` (修改)

**验收标准**:
- [ ] 中英文翻译已添加
- [ ] 组件正确使用翻译键
- [ ] 语言切换时翻译正确更新

---

## Phase 5: 测试与验证

### T5.1 功能测试

**优先级**: 高
**预计工作量**: 30 分钟
**依赖**: T4.2

**描述**:
验证核心功能正常工作。

**测试用例**:
- [ ] 应用启动后自动加载 RSS 数据
- [ ] 博客文章正确显示(标题、日期、摘要)
- [ ] 最多显示 5 条文章
- [ ] 点击文章在浏览器中打开
- [ ] 刷新按钮能手动更新数据
- [ ] 最后更新时间正确显示

---

### T5.2 错误处理测试

**优先级**: 高
**预计工作量**: 20 分钟
**依赖**: T5.1

**描述**:
验证错误场景的处理。

**测试用例**:
- [ ] 网络断开时显示错误提示
- [ ] RSS 源不可用时显示友好消息
- [ ] RSS 格式错误时有降级处理
- [ ] 加载状态正确显示

---

### T5.3 国际化验证

**优先级**: 中
**预计工作量**: 10 分钟
**依赖**: T5.1

**描述**:
验证国际化功能。

**测试用例**:
- [ ] 中文界面翻译正确
- [ ] 英文界面翻译正确
- [ ] 语言切换时组件正确更新

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Mark completed tasks with - [x] once verified.
Many items appear implemented in this PR but remain unchecked.

Based on learnings: Applies to openspec/changes/*/tasks.md : Update every task in tasks.md to - [x] after all implementation work is complete and confirmed.

🧰 Tools
🪛 markdownlint-cli2 (0.20.0)

[warning] 240-240: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
In
`@openspec/changes/archive/2025-02-10-official-blog-rss-feed-integration/tasks.md`
around lines 49 - 381, Update the checklist items in this tasks.md to mark
completed work as done by changing "- [ ]" to "- [x]" for tasks that have been
fully implemented and verified (e.g., the T1.2, T2.1-T2.3, T3.1-T3.2, T4.1-T4.3,
T5.1-T5.3 entries and their sub-items); ensure you only flip boxes after
confirming implementation and tests, update all instances under
openspec/changes/*/tasks.md, and include a brief commit message like "mark RSS
feature tasks completed" when committing the changes.

Comment thread package.json
"dev:main": "tsc --watch",
"dev:preload": "vite build --config vite.preload.config.ts --watch",
"dev": " npm run predev && rm -rf dist && concurrently -k \"npm run dev:renderer\" \"npm run dev:main\" \"npm run dev:preload\" \"wait-on dist/preload/index.mjs && wait-on dist/main/main.js && cross-env NODE_ENV=development HAGICO_CONFIG_PATH=local_data_root electron .\"",
"dev": "rm -rf dist && concurrently -k \"npm run dev:renderer\" \"npm run dev:main\" \"npm run dev:preload\" \"wait-on dist/preload/index.mjs && wait-on dist/main/main.js && cross-env NODE_ENV=development HAGICO_CONFIG_PATH=local_data_root electron .\"",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Make the dev script cross‑platform (Windows-safe).
rm -rf will fail on Windows shells; use a Node-based delete instead.

🔧 Suggested change
-    "dev": "rm -rf dist && concurrently -k \"npm run dev:renderer\" \"npm run dev:main\" \"npm run dev:preload\" \"wait-on dist/preload/index.mjs && wait-on dist/main/main.js && cross-env NODE_ENV=development HAGICO_CONFIG_PATH=local_data_root electron .\"",
+    "dev": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\" && concurrently -k \"npm run dev:renderer\" \"npm run dev:main\" \"npm run dev:preload\" \"wait-on dist/preload/index.mjs && wait-on dist/main/main.js && cross-env NODE_ENV=development HAGICO_CONFIG_PATH=local_data_root electron .\"",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"dev": "rm -rf dist && concurrently -k \"npm run dev:renderer\" \"npm run dev:main\" \"npm run dev:preload\" \"wait-on dist/preload/index.mjs && wait-on dist/main/main.js && cross-env NODE_ENV=development HAGICO_CONFIG_PATH=local_data_root electron .\"",
"dev": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\" && concurrently -k \"npm run dev:renderer\" \"npm run dev:main\" \"npm run dev:preload\" \"wait-on dist/preload/index.mjs && wait-on dist/main/main.js && cross-env NODE_ENV=development HAGICO_CONFIG_PATH=local_data_root electron .\"",
🤖 Prompt for AI Agents
In `@package.json` at line 21, The dev script uses the POSIX-only rm -rf which
breaks on Windows; update the "dev" npm script to use a cross-platform deletion
tool (e.g., replace rm -rf dist with rimraf dist or use shx rm -rf dist) and add
the corresponding devDependency (e.g., rimraf) so npm run dev works on Windows,
keeping the rest of the concurrently command and the referenced scripts
("dev:renderer", "dev:main", "dev:preload") unchanged.

Comment on lines +176 to +180
>
<div
onClick={() => handleArticleClick(item.link)}
className="p-3 rounded-lg border border-border/50 hover:border-primary/50 hover:bg-accent/5 transition-all cursor-pointer"
>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Make article tiles keyboard-accessible.
The clickable <div> only supports mouse input, so keyboard users can’t open articles. Prefer a semantic <button>/<a> (or add role/tabIndex/keydown handling).

✅ Suggested fix (semantic button)
-              <div
-                onClick={() => handleArticleClick(item.link)}
-                className="p-3 rounded-lg border border-border/50 hover:border-primary/50 hover:bg-accent/5 transition-all cursor-pointer"
-              >
+              <button
+                type="button"
+                onClick={() => handleArticleClick(item.link)}
+                className="w-full text-left p-3 rounded-lg border border-border/50 hover:border-primary/50 hover:bg-accent/5 transition-all cursor-pointer"
+              >
                 <div className="flex items-start justify-between gap-3">
                   <div className="flex-1 min-w-0">
                     <h4 className="text-sm font-medium text-foreground group-hover:text-primary transition-colors line-clamp-2">
                       {item.title}
                     </h4>
@@
                 </div>
-              </div>
+              </button>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
>
<div
onClick={() => handleArticleClick(item.link)}
className="p-3 rounded-lg border border-border/50 hover:border-primary/50 hover:bg-accent/5 transition-all cursor-pointer"
>
>
<button
type="button"
onClick={() => handleArticleClick(item.link)}
className="w-full text-left p-3 rounded-lg border border-border/50 hover:border-primary/50 hover:bg-accent/5 transition-all cursor-pointer"
>
🤖 Prompt for AI Agents
In `@src/renderer/components/BlogFeedCard.tsx` around lines 176 - 180, The article
tile uses a clickable div which is not keyboard-accessible; update the
BlogFeedCard so the interactive container uses a semantic element (prefer an <a>
or <button>) or at minimum adds role, tabIndex and key event handling; replace
the clickable <div> that calls handleArticleClick(item.link) with a semantic
element (e.g., an anchor linking to item.link or a button that calls
handleArticleClick) and ensure focus styles/hover classes are preserved and
Enter/Space key activation is supported if you choose a non-semantic element;
reference the interactive container around handleArticleClick and the item.link
usage when making the change.

newbe36524 added a commit that referenced this pull request Feb 10, 2026
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Added official blog RSS feed integration displaying the latest blog
posts within the app
  * Automatic feed refresh every 24 hours with manual refresh capability
  * Offline caching for continuous access to blog posts
* Multi-language support for the blog feed interface (English and
Chinese)

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant