Product & architecture documentation

功能看得见,
边界让它走得远。

这里从当前源码出发,说明阅读表面下方的三层解耦:字段时钟同步、受约束的内容 Connector,以及与运行环境和存储实现分离的共享界面。

当前产品状态

开发预览 · Local-first
主要存储
每设备 SQLite
AI 与同步
可选
主要品质目标
macOS
最近核对
2026 年 7 月 31 日
01 系统概览

每台设备都拥有完整的阅读库。

云端可以提供帮助,但不会成为唯一的数据源。阅读、收藏、搜索与知识记录都先从设备本地开始。

01 协议边界

同步操作与字段时钟

设备交换持久意图与用户状态,不复制 SQLite 文件、文章正文、索引或模型缓存。

沿着合并路径往下看 ↓
02 来源边界

Connector 先声明自己需要什么

带版本的 descriptor、统一内容模型与受约束网络上下文,把来源适配和本地存储分开。

查看契约细节 ↓
03 运行时边界

一套界面,可替换的数据 Adapter

React 依赖平台能力与 Reader Repository,不直接判断操作系统,也不绑定某一种数据库 transport。

查看 Adapter 层次 ↓
你的设备
界面React 阅读表面电脑 · 平板 · 手机
边界Platform + Repository当前 HTTP · 迁移原生 SQLite
主要存储SQLite文章 · 状态 · 知识 · 索引
正文抓取队列翻译缓存向量队列加密备份
可选知识库Obsidian受控 Markdown 区块
可选智能AI Provider明确同意后才发送
可选多端Rinwa Sync同步操作,不复制 SQLite
迁移中的边界

桌面与 Web 当前仍以本地 Node API 为完整生产路径。移动 SQLite Adapter 已能编译,但完整阅读路径切换与真实设备验证尚未完成。

已经实现

当前源码中存在,并通过已有构建或测试验证。

可选

默认关闭,或只在用户主动配置后使用。

早期基础

今天已经有用,但范围刻意小于未来的完整系统。

尚未发布

共享实现已经存在,打包、签名、商店或设备验证仍未完成。

02 阅读与订阅

文章开始以后,阅读器安静退后。

已经实现

Rinwa 围绕阅读,而不是提醒压力来组织订阅。未读通过字重与颜色表达;操作只在需要时出现,不用红点把每篇文章变成任务。

阅读表面

保留原文结构

标题、段落、列表、引文、代码、表格、图片和媒体按原来的顺序呈现。全文抽取异步进行;刷新失败时,缓存或 Feed 内容仍然可以阅读。

阅读入口

今天、未读、收藏与单订阅

智能视图与分组、单订阅阅读并列存在。订阅可以不进入聚合首页,但不会因此被删除;未读数量保留在本机。

订阅管理

健康状态、历史与偏好

可查看最近尝试与成功时间、HTTP 状态、连续失败、文章总数与新增数,并设置分组、目标语言和自动 AI 偏好。

可迁移

OPML 导入与导出

导入包含预览、选择、重复处理与分组保留;导出仍是普通 OPML,让其他阅读器可以理解。

来源识别

站点图标与安静回退

能够取得时显示站点 favicon;加载失败时使用简洁的来源首字,不留下破损图片。

命令面板 · ⌘K

用键盘完成导航与操作

打开智能视图、分组、订阅与保存搜索;添加或管理订阅;切换已读和收藏;打开原文;或把当前列表全部标记已读。搜索词同时包含中英文别名。

01进入

RSS、Atom、JSON Feed 与内置 Connector 都进入统一内容模型。

02保留

先保存 Feed 副本;全文抽取可以改进它,但不会删除上一份成功正文。

03阅读

智能视图与来源视图共用同一套阅读器、键盘、触控和触控板交互。

03 原文优先翻译

原文不等待译文。

可选 · 需要同意

文章先显示原文。译文异步出现在对应段落下方,保留原文作为证据,而不是把页面替换成另一种语言。

始终先出现 原文区块

结构、媒体、链接与可执行代码仍属于作者原文。

随后
准备好再出现 译文区块

对齐在原文下方;失败不会遮住原文。

跳过规则

中文、代码与预格式化区块、只有 URL 的内容、日期、数字、纯标点和没有自然语言价值的文本不会送去翻译。

每个订阅独立语言

每个订阅保存自己的目标语言。自动翻译按订阅单独开启,并在全文缓存完成后运行。

Provider 可选择

可以使用环境配置、DeepL、OpenAI-compatible 翻译或自定义端点。Provider 与模型设置不会侵入阅读表面。

不配置 Provider 也能阅读

没有翻译服务时,Rinwa 仍是完整的本地阅读器。开发环境中的确定式回退不会被包装成高质量人工翻译。

05 AI 阅读助手

先组织证据,再调用 Provider。

BYOK · 需要同意

AI 辅助首先在本地构造有限上下文。短文章可以使用全文,长文章与全库问题则先检索段落;文章坐标和知识记录会先变成引用 ID,再交给用户选择的服务。

文章划线笔记全库搜索
本地上下文构造器 范围 → 检索 → token 预算 → 引用 ID
[P] 文章[H] 知识[S] 全库
↓ 明确同意
OpenAIOpenRouterOllamaCustomDeepL
流式回答引用校验 · 重试策略 · 用量统计
上下文范围

摘要、文章、文章+知识或全库

范围由用户明确选择。短文章可以完整进入上下文;长文章与全库问题在固定输入预算内检索相关段落。

透明证据

段落、划线与全库引用

文章段落使用 [P],保存划线使用 [H],其他文章使用 [S]。没有出现在本次上下文中的引用 ID 会在展示前移除。

对话记忆

近期原文+有界滚动记忆

最近消息在单条预算内保留原文;更早的用户问题压缩成简短提醒,旧的助手回答不会被当作证据。

回答控制

简洁、平衡或深入

可以选择回答语言、风格、上下文范围、引用、temperature、token 上限,以及 Provider 支持的 reasoning effort。

Provider 选择

OpenAI、OpenRouter、Ollama 或自定义

Rinwa 通过 OpenAI-compatible /models 发现模型,并传递受支持的 reasoning effort,不把界面绑定到单一厂商。

没有 Provider

本地阅读仍然可用

非 AI 路径与开发环境保留确定式本地回退。没有配置服务,只意味着没有外部回答,不会让内容库失效。

自动 AI 仍然是一次外发请求

每个订阅的自动翻译与自动摘要默认关闭,需要当前版本的数据共享同意,并显示后台 token 成本提示。AI 可以建议笔记内容,但不能未经确认直接修改。

06 保存搜索 → 虚拟订阅

一个问题,可以变成长期更新的阅读流。

已经实现

保存搜索把结构化本地查询变成持续更新的虚拟订阅。它出现在智能视图旁边,拥有自己的未读数量,并使用普通文章列表与阅读器。

关键词AND订阅或分组AND作者或域名AND已读 / 收藏AND时间 / 标签

可解释的筛选

V1 使用 AND 条件,不用不透明的 AI 规则:关键词、订阅、分组、作者、域名、已读状态、收藏、24 小时 / 7 天 / 30 天与标签。

设备之间可迁移

查询保存订阅的稳定 global ID,而不是某台设备的数据库行号,因此可以通过 operation log 同步。

共享查询基础

服务端使用同一个 resolver,让侧栏、未读数、全部标记已读、备份、同步和未来自动化保持同一套含义。

07 划线与稳定锚点

宁可暂时无法定位,也不画错位置。

已经实现

Rinwa 保存选中文字与有限的前后文。当全文抽取改变 HTML 时,会跨区块与行内元素保守地重新定位完全匹配的规范化文本。

保存的证据quote + prefix + suffix
本地重新锚定精确文本 + 上下文评分
结果已定位,或明确未定位
正文变化以后

分段行内标记

一处划线可以跨多个文本节点或行内元素。Rinwa 把它渲染成一个可访问的逻辑划线,不会把文章结构压平。

重复文本

前后文消歧

重复句子会根据保存的 prefix 与 suffix 评分。证据太弱或为空时保持未定位,不会直接选择最早出现的位置。

回到证据

跳转到原文

选择保存划线后,知识面板先关闭,再把对应原文标记滚动到阅读区中央,并遵守减少动态效果偏好。

行内附注

只读弹出层

激活标记后显示保存的附注,或者安静的“无附注”状态。V1 不在这里提供编辑或单条划线删除。

08 知识、Obsidian 与 MCP

阅读结果可以离开应用。

已经实现

收藏文章可以带有可编辑摘要、个人笔记、标签、划线、译文摘录与外部引用。这些是用户数据,不是可以随时清理的 AI 输出。

Obsidian 双向往返

Rinwa 只写入清楚标记的受控区块,保留周围的用户 Markdown;Vault 中的修改可以通过本地同步 worker 回到 Rinwa。

安全移除

移除知识条目会取消收藏并删除对应受控记录。导出的 Vault 文件默认保留,只有用户明确勾选时才一起删除。

stdio 本地 MCP

独立本地进程向 AI agent 提供订阅、文章、搜索、知识、标签、统计、健康状态与 OPML。安全写入需要本地 token;破坏性操作和 Rinwa 的外部 AI 调用不会暴露。

MCP 通过 Rinwa 本地 HTTP API 工作,不直接打开 SQLite。它面向桌面与本地开发环境,不作为移动端进程运行。

09 内容来源 Connector

插件边界,先从更少权限开始。

P0/P1 基础

SourceConnector 把特定来源的发现和拉取,与 Rinwa 数据库分开。RSS 与公开 YouTube 通过同一个 registry factory 注册,也实现未来 Connector 会使用的同一套接口:probediscoverresolveSubscriptionpullEntries

声明 ConnectorDescriptor 身份 · API 版本 · 能力 · 权限 · 速率限制
Host 授予的表面 ConnectorContext 一个受约束的 fetch();没有数据库或文件系统句柄
可移植输出 ConnectorEntry 稳定远端 ID · 正文完整度 · 媒体 · 抽取策略

Capability 描述行为

V1 契约识别发现、URL 解析、增量拉取、认证、内嵌正文与媒体资源。未知能力会让 descriptor 校验失败,不会悄悄扩大权限。

网络与节奏显式声明

Descriptor 包含允许访问的 host、最小请求间隔、最大并发与可选分页大小。当前 Host 创建 fetch context 时会使用声明的网络 host。

SDK 不依赖应用实现

Descriptor、订阅意图、内容条目、媒体资源、请求响应与 JSON 消息 ABI 都位于 packages/connector-sdk,存储仍由 Host 负责。

最少query

可以接收发现来源所需的用户查询文字或 URL 输入。

限定范围source-id

可以处理已订阅远端来源的稳定标识。

最敏感article-body

为确实需要正文的 Connector 预留显式文章文本权限。

这些层级目前是权限词汇,不代表正文接口已经开放。两个内置 Connector 都只声明 querysource-id;当前 ConnectorContext 根本没有提供 article body API。

01

每一跳都重新检查

Redirect 由 Host 手动跟随。下一次请求前会再次检查协议、声明的 host 策略与公网地址,不能只验证起点。

02

拒绝私有网络

Loopback、私网、link-local、运营商级 NAT、云 metadata 以及对应 IPv6 范围都会被拒绝,避免 Connector 成为访问用户局域网的通道。

03

限制响应边界

Direct context 最多跟随 5 次跳转,正文上限 8 MiB,请求超时 15 秒。跨 origin 跳转时会移除敏感 header。

04

规范化以后再存储

Connector 输出进入 RSS 也使用的 ingestion service,让稳定 ID、内容哈希、媒体、抽取策略与后续索引保持同一含义。

早期边界,不是插件市场

RSS 与 YouTube 证明这套接口确实在用,不只是计划。但 Connector 仍内置在 API 进程中:还没有第三方包加载器,也没有针对任意代码的安全沙箱。DNS rebinding 也仍有已记录的 TOCTOU 限制,要等到解析地址能固定到实际 socket 才能消除。

10 备份与还原

既能带走,也能带回来。

已经实现

备份与同步彼此独立。可以只保存易读的订阅配置,也可以创建包含用户阅读与知识数据的完整加密快照。

仅订阅

可读导出

订阅、分组、聚合设置、目标语言与自动 AI 偏好以明文文件导出。

完整内容库

AES-256-GCM

口令经过 scrypt 加强,再使用随机 salt、nonce 与带认证的加密保护完整备份。

还原方式

合并或替换

合并会在适当位置保留本地记录;替换在事务中执行,避免留下只完成一半的破坏性状态。

定时备份

桌面本地文件夹

可以每天或每周写入用户选择的文件夹,保留指定数量,并把口令放在操作系统安全存储中。

Web 开发模式提供手动下载与上传。当前备份实现不包含移动端后台定时。

11 可选多端同步

同步操作,不复制数据库文件。

可选服务器

每台设备都能独立使用。本地修改在上传前先记录成 operation,包含稳定 ID、实体、动作、JSON payload、设备序列、时间与 HLC 排序键。服务器中继日志;每台客户端再把它合并进自己的 SQLite。

设备 ASQLite本地写入
operation 队列
pushpull
RINWA SYNCCouchDB不可变、幂等的 operation log
不解析 _changes cursor
pullpush
设备 BSQLite本地写入
字段时钟合并
01

记录

deviceId:sequence、实体、动作、payload、时间和 HLC 先写入本机。

02

中继

服务器验证有界批次;重复 operation ID 只会成为无害的 CouchDB conflict。

03

按字段合并

sync_field_clocks 为每个实体字段保存一枚 HLC;shouldApplyField 只推进更晚到达的那个字段。

04

记住删除

deleted 字段时钟在数据行消失后仍保留。旧 upsert 不能复活它,真正更新的重新添加可以。

当前协议实体

connector_subscriptionfeedhighlight item_stateitem_summaryknowledge preferencesread_later_capturereading_position rulesaved_search
createHlc() 生成的排序键 epochMillis:sequence:deviceId
物理时间

13 位 epoch 毫秒提供大致时间顺序。

逻辑序列

每设备 sequence 让同一毫秒内产生的多次操作也能有序。

确定式消歧

device ID 让时间与序列都相同时,在所有客户端得到相同比较结果。

只用墙上时钟会产生相同时间戳,不同设备也可能对当前时间意见不一。Rinwa 当前的 HLC 形态键保证确定式字符串排序,但不会消除时钟漂移:设备时间严重错误时,仍可能影响同一字段哪次写入被认为更新。

设备 AisRead = true推进 isRead 时钟
设备 BisStarred = true推进 isStarred 时钟
合并后的文章状态已读,同时已收藏两次无关修改都保留下来

朴素的整行 last-writer-wins 会覆盖整条 item state,让其中一次修改丢失。Rinwa 分字段比较;只有两台设备修改同一字段时,才由更新的 HLC 决定结果。

只同步意图

传订阅与 URL,不传抓取正文

Connector 订阅携带来源身份与设置;稍后读携带 URL 与 capture 时间。接收设备各自在本地抓取和保存结果,减少私密正文复制与带宽消耗。

原子逻辑字段

必须一致的值共用一枚时钟

阅读位置用一个 anchor 时钟覆盖文章 ID 与排序键;稍后读用一个 capture 时钟覆盖 URL 与 capture 时间,避免把两次写入拼成一组。

本地物化

日志记录意图,Service 完成工作

新导入订阅会在本机安排抓取;稍后读的网络抓取离开 apply loop 排队执行,不让 operation 应用变成破坏性或阻塞步骤。

删除也参与排序

Tombstone 决定删除还是重新添加

Feed、知识、Connector、保存搜索、阅读位置、规则、划线与稍后读的删除路径都会推进 deleted,阻止旧快照把记录复活。

以 OPERATION 同步

Feed 与 Connector 意图 · 文章状态与摘要 · 知识与划线 · 阅读偏好与位置 · 规则 · 保存搜索 · 稍后读 capture

每设备独立物化

文章正文 · 抽取 HTML · 媒体 · 翻译 · 模型文件 · 向量 · 全文与向量索引

客户端开源,托管连续性可选付费

Rinwa 由 kappain 以开源阅读器的方式开发;托管 Rinwa Sync 是计划中的商业服务。本地阅读不依赖它,自托管能力也继续留在协议边界内。

远端向量搜索尚未启用

服务器可以创建 Qdrant Collection,但协议仍明确返回 semanticSearch: false。当前语义检索发生在本地,远端集合存在不等于功能已经上线。

12 本地优先隐私与缓存

应用版本与内容版本彼此独立。

核心约束

每台设备以 SQLite 作为主要存储。修改界面、增加设置或修复手势不会清空文章;正文抽取、翻译、生成摘要和向量分别拥有自己的兼容版本。

层级何时失效失败行为
Feed 内容上游内容哈希改变保留当前 Feed 副本
阅读正文抽取契约与正文哈希改变保留上一份成功正文
翻译管线、目标语言或正文哈希改变原文继续可读
生成摘要摘要契约、语言或正文哈希改变手工摘要不受影响
向量模型、revision、分块或向量契约改变搜索回退到 FTS
外部发送需要明确同意

翻译、摘要与问答在当前数据共享版本被接受前不会发送内容;用户可以撤回同意。

密钥不进入内容存储

打包桌面客户端使用操作系统安全存储保存 Provider Key 与同步 token。旧明文字段只用于迁移,不是继续复制的设计。

私密正文不进入日志

文章正文、prompt、API Key、同步 token 与 Vault 内容都不应记录。

数据库只做增量迁移

已有数据库原地升级;开发过程不会删除或重建用户内容库。

用户数据长期保留

笔记、标签、划线、引用与手工编辑摘要不会被当作可丢弃的生成缓存。

导出路线一直存在

OPML、Obsidian 与备份提供真正可用的离开路径。

13 多端架构

一套界面,两处可替换边界。

移动端尚未发布

React 与 Vite 提供共享阅读表面,Tauri 2 将它交付到桌面与移动端。存储 transport 隐藏在 ReaderRepository 后面;运行时能力隐藏在 PlatformAdapter 后面。组件应该询问“能做什么”,而不是判断操作系统名字。

共享 REACT UI订阅 · 文章 · 状态 · 设置只依赖一个接口
数据契约ReaderRepositorylistFeeds · getItems · 写操作
当前路径HttpReaderRepository浏览器 + 桌面本地 API
移动端基础SqliteReaderRepository原生 tauri-plugin-sql

Repository 在运行时选择

getReaderRepository() 只在壳报告 native API transport 且存在本地 SQL 能力时选择 SQLite;其他环境都得到 HTTP 实现。

接口刻意保持窄小

当前阅读核心覆盖订阅列表、文章查询、已读/收藏、订阅设置与删除。AI、知识、OPML 和同步仍是接口之外的远端操作。

切换尚未完成

主要订阅读取与订阅设置写入已经通过 Repository;分散的文章状态调用、iOS/Android 真机验证,以及移动数据库填充路径仍未完成。

共享 UIReact · 响应式阅读 · 手势 · 知识
Platform Adaptertransport · 链接 · 分享 · 目录 · 安全存储 · 后台刷新 · 本地 SQL
macOSWindowsiOS / iPadOSAndroid
报告能力,不虚构成功

浏览器 Adapter 在合适位置返回 falsenull,安全存储与应用内浏览不可用时抛出 PlatformCapabilityError。原生壳可以覆盖 capability map,不需要假装每个平台都已完成。

macOS · 主要品质目标

共享界面与桌面壳已经存在,包括原生窗口、目录选择、SQLite Bridge、安全存储基础和原生网页窗口;目前仍没有签名、notarized 的正式安装包。

Android · 开发预览

共享界面可以打包,但本地 SQLite 完整切换、Keystore、后台刷新、真实设备验证、签名与商店发布仍未完成。

iOS / iPadOS 与 Windows · 已实现共享基础,尚未发布

它们复用同一套 React/Tauri 架构;原生构建、数据库填充、签名、设备验证与分发流程仍未完成。

14 与源码同步的技术参考

实现细节直接由产品仓库文档生成。

构建校验

下面的页面来自 feedsuite 中选定的 Markdown 文档。官网构建会自动重新生成页面、检查站内链接并打包产物,不再需要在两个仓库里手工复制。

编排式指南 + 自动生成的实现依据

当前页面继续负责清晰解释产品;参考页承载更细的实现信息,并链接到 GitHub 中的源文档。

15 真实能力状态

已经实现,不等于已经发布。

当前源码已经实现

阅读与订阅管理、OPML、原文优先翻译、多 Provider AI、本地混合检索、保存搜索、稳定划线锚点、知识与 Obsidian、本地 MCP、P0/P1 Connector 与 YouTube、加密备份、operation log 同步、命令面板和共享响应式 UI。

刻意保持早期或可选

本地向量需主动开启;AI 与同步需要配置;Connector 是 P0/P1 内置基础,不是市场;Android 是开发预览。

尚未交付

移动端原生后台刷新、完整 Android Keystore 验证、移动 SQLite 全面切换与填充、签名/notarized macOS 安装包、iOS 与 Windows 正式包、商店提交,以及第三方 Connector 市场。

需要实现级别的细节?

在 GitHub 阅读源码 ↗