Daily News Digest
这是一个面向个人服务器的资讯日报项目,第一阶段不接入 AI:n8n 负责定时抓取 RSS,按关键词分类、去重并写入 PostgreSQL;网页读取 PostgreSQL 展示当天和历史记录;邮件发送当天完整日报。
当前范围
- AI 与 Agent
- 农业硬件
- 农业方案落地
- 农业服务
- 政策与市场
- 国内与国际资讯
数据库初始化
- 在 PostgreSQL 中创建一个独立数据库和用户,例如
news_digest/news_app。 - 使用
db/schema.sql建表:
psql -h 127.0.0.1 -p 15432 -U news_app -d news_digest -f db/schema.sql
Windows PowerShell 示例:
psql -h 127.0.0.1 -p 15432 -U news_app -d news_digest -f .\db\schema.sql
如果 PostgreSQL 不在本机,先建立 SSH 隧道:
ssh -N -L 15432:127.0.0.1:5432 <ssh-user>@<server-ip>
这会把本机 127.0.0.1:15432 转发到 SSH 服务器可访问的 127.0.0.1:5432。数据库本身不需要暴露公网端口。
Docker 中访问 SSH 隧道
如果 n8n 或网页容器运行在 Docker 中,容器里的 127.0.0.1 指向容器自身,不是宿主机。此时:
- Linux Docker:让隧道监听宿主机地址,并将
host.docker.internal映射到宿主机网关; - Docker Desktop:通常可直接使用
host.docker.internal; .env中的PGHOST应填写host.docker.internal,PGPORT填写隧道本地端口(默认15432)。
本项目不会自动保存或生成 SSH 私钥。建议使用 systemd、Windows 服务或 Docker sidecar 管理 SSH 隧道,并为隧道设置自动重连。
Linux 云服务器上推荐使用 docker-compose.host-network.yml:SSH 隧道监听宿主机 127.0.0.1:15432,网页容器使用宿主机网络,.env 中填写 PGHOST=127.0.0.1、PGPORT=15432。这样不会把数据库隧道端口暴露到公网。模板见 deploy/daily-news-db-tunnel.service.example。
网页服务可由 Nginx 代理到宿主机本地端口。使用 docker-compose.host-network.yml 时,覆盖配置会让网页只监听 127.0.0.1:3100;不要直接把 3100 暴露给公网。
配置
复制 .env.example 为 .env,再在服务器上填写实际值。仓库中不提交 .env、密码、SMTP 授权码或 SSH 私钥。
当前完成度
- 网页日报和历史查询已完成
- 收件邮箱、多模块订阅设置已完成
- PostgreSQL 访问层和 Docker 部署配置已完成
- n8n RSS 抓取、日报生成和 SMTP 发送工作流待接入
网页和邮件会读取同一份 PostgreSQL 数据,因此当天内容与历史记录保持一致。
news_articles.category 用于主要栏目;news_articles.topics 支持一篇文章同时标记多个主题,例如同时属于 ai_agent 和 agri_solutions。历史搜索由网页服务使用 ILIKE 查询标题、摘要和关键词,避免依赖 PostgreSQL 内置的中文分词。
外文翻译是可选的独立步骤,不等同于 AI 内容分析。news_articles.title 和 summary 保留原文;translated_title 和 translated_summary 保存中文翻译。translation_status 记录是否翻译成功。翻译服务可以使用阿里云机器翻译、DeepL、Google Cloud Translation,或以后改成本地翻译服务;API 密钥只放在服务器 .env 中。
用户和邮件订阅
app_users 保存网页用户账号;密码只保存 Argon2id/bcrypt 哈希,不保存明文密码。newsletter_recipients 保存实际收件邮箱,recipient_modules 是邮箱与模块的多对多关系,因此一个邮箱可以选择多个模块。newsletter_modules 是可扩展的模块目录。
如果原始 schema.sql 已经执行过,请按顺序执行:
db/migrations/002_users_and_subscriptions.sql
db/migrations/003_translation_fields.sql
不要为了增加用户功能删除已有表。以后新环境从零创建时,直接执行完整的 db/schema.sql 即可。
示例:创建一个收件邮箱并订阅多个模块:
INSERT INTO newsletter_recipients (email, display_name)
VALUES ('your@example.com', '我的日报')
RETURNING id;
-- 将上一步返回的 id 替换为 1
INSERT INTO recipient_modules (recipient_id, module_key)
VALUES
(1, 'ai_agent'),
(1, 'agri_solutions'),
(1, 'agri_services');
Gitea 部署方式
项目完成后,将整个 daily-news-digest 目录作为一个独立仓库推送到 Gitea。服务器只保存运行所需的工作副本,实际配置文件 .env 在服务器本地填写,不提交到 Gitea。
推荐的第一阶段流程:
本地修改
↓
提交并推送到 Gitea
↓
服务器 git pull
↓
docker compose up -d --build
使用 Linux 主机网络时改为:
docker compose -f docker-compose.yml -f docker-compose.host-network.yml up -d --build
后续如果启用 Gitea Actions 或 Woodpecker CI,可以把最后两步自动化;在当前没有业务代码、需要先稳定运行的阶段,先采用服务器手动拉取更新更容易排错。
服务器首次部署时大致是:
git clone <你的 Gitea 仓库地址> /opt/daily-news-digest
cd /opt/daily-news-digest
cp .env.example .env
# 只在服务器本地填写 .env
docker compose up -d --build
SSH 隧道、PostgreSQL 密码、SMTP 授权码都不放进仓库;Gitea 只管理源码、SQL、工作流模板和部署文件。
网页和收件人设置
网页服务默认监听 3000 端口。部署前在服务器 .env 中填写:
APP_ADMIN_TOKEN=请设置一个随机的长令牌
打开 /settings 后输入这个令牌,即可添加、编辑和删除收件邮箱,并为每个邮箱选择一个或多个推送模块。令牌只保存在当前浏览器会话中;没有配置令牌时,邮箱管理接口会拒绝请求。
日报页面地址为 /,设置页面地址为 /settings。网页只读取 PostgreSQL 中的日报和订阅设置,邮件实际发送仍由后续 n8n 工作流完成。