文海问津创新实训项目记录(二)
这次做了两部分的内容,一个是对于管理员用户,用户管理和邮件部分的设置,另一部分是对于每日帖子自动生成这个板块的初步实现
一 管理端:用户管理与邮件模板设置
本文记录管理员端两块能力:
- 用户管理(禁用/启用、会话失效)
- 邮件模板设置(注册验证码 / 找回密码验证码 / 绑定邮箱验证码)
1. 目标与边界
目标:
- 管理员可统一管理用户状态,快速处理异常账号
- 管理员可按场景分别配置验证码邮件内容
- 模板支持占位符,避免每次改代码发版
边界:
- 当前仅支持验证码类模板,不包含营销/通知类模板
- 模板变量目前固定为 {{purpose}}、{{code}}、{{minutes}}
2 .用户管理(Admin Users)
前端入口:
- 路由:/admin/users
- 页面:AdminUsersPage
后端接口:
- GET /api/v1/admin/users
- PATCH /api/v1/admin/users/{userId}(更新 status)
- POST /api/v1/admin/users/{userId}/revoke-tokens(使 token 失效)
权限模型:
- 依赖网关注入 X-User-Roles
- ADMIN 才可访问上述接口
3 .邮件模板设置(Admin Mail Templates)
前端入口:
- 路由:/admin/settings/mail
- 页面:AdminMailSettingsPage
后端接口:
- GET /api/v1/admin/settings/mail-templates/types
- GET /api/v1/admin/settings/mail-templates/{templateType}
- PUT /api/v1/admin/settings/mail-templates/{templateType}
支持的模板类型:
- REGISTER_VERIFICATION
- PASSWORD_RESET_VERIFICATION
- BIND_EMAIL_VERIFICATION
模板存储:
- 表:pf_mail_template
- Flyway新增脚本:
- V6__mail_template_settings.sql(建表 + 兼容旧模板)
- V7__mail_template_multi_types.sql(新增三类模板初始数据)
4 .发送链路如何命中对应模板
验证码发信时,后端会按业务场景传入模板类型:
- 注册验证码:REGISTER_VERIFICATION
- 找回密码验证码:PASSWORD_RESET_VERIFICATION
- 绑定邮箱验证码:BIND_EMAIL_VERIFICATION
MailService 通过 MailTemplateService 渲染标题和正文,再交给 Spring Mail 发送。
5 .运维与排查建议
- 若管理页更新模板后无效果,先确认当前环境 PF_MAIL_ENABLED=true
- 若启动报 Flyway checksum mismatch,不要修改已执行版本,新增更高版本迁移
- 模板文本建议保留占位符,避免发出无验证码的无效邮件
二 内容服务:每日帖子自动生成(Scheduler)
1. 功能目标
- 每天自动生成一条“每日更新”帖子,作为前端 /posts 页面的内容来源
- 当前实现为占位版本(便于先跑通端到端闭环)
- 后续可替换为 Curator/Editor Agent 产出的内容(网关转发下游 Agent,不在本次范围)
2 .端到端行为
- 定时任务触发(默认每天 UTC 09:00)
- 检查当天是否已有帖子
- 若没有,写入一条新帖子(source=scheduler)
3 .关键代码原文 + 解读
代码位置:[DailyPostJob.java](file:///f:/Gitee/PaperFlow/PaperFlow/backend/services/content-service/src/main/java/com/paperflow/content/job/DailyPostJob.java)
@Component
public class DailyPostJob {
private final PostRepository posts;
public DailyPostJob(PostRepository posts) {
this.posts = posts;
}
@Scheduled(cron = "0 0 9 * * *")
public void ensureDailyPost() {
OffsetDateTime now = OffsetDateTime.now(ZoneOffset.UTC);
OffsetDateTime start = now.truncatedTo(ChronoUnit.DAYS);
OffsetDateTime end = start.plusDays(1);
if (posts.existsByPublishedAtBetween(start, end)) {
return;
}
PostEntity p = new PostEntity();
p.setId("post_" + UUID.randomUUID().toString().replace("-", ""));
p.setTitle("Daily Update " + start.toLocalDate());
p.setContent("This is an auto-generated daily post placeholder.");
p.setSource("scheduler");
p.setPublishedAt(now);
posts.save(p);
}
}
逐段解释:
- @Scheduled(cron = "0 0 9 * * *"):每天 09:00 触发一次(当前以服务端进程时间为准)。
- OffsetDateTime.now(ZoneOffset.UTC):
- 明确以 UTC 作为“每日”划分基准,避免部署到不同时区后“日界线错乱”。
- start/end:
- 用“当天 00:00:00”到“次日 00:00:00”定义当天范围;
- 配合 existsByPublishedAtBetween 判断当天是否已生成过帖子。
- 生成帖子:
- id 外部可用稳定字符串,不暴露自增主键;
- source=scheduler 方便追踪帖子来源(未来会出现 curator_push、editor_digest 等)。
另外,现在是用 ZoneOffset.UTC 写死时间。但 服务器时区必须与 UTC 对齐,否则 cron 表达式仍会以本地时区执行,导致每日帖子生成时间与预期不符
4 演进方向
- 幂等增强:把“每日唯一性”改成数据库唯一约束(例如 published_date 唯一),更抗并发/重启
- 内容生成替换:
- 由 Curator 选题 → Editor 生成摘要/配图 → content-service 入库
- 调用通过网关转发到 Agent 服务
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)