feat: add blog CMS and AI animation renderer#18
Open
wangschang wants to merge 1 commit into
Open
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PR:博客 CMS 后台与 AI HTML 动画生成/视频渲染
1. 变更摘要
本 PR 在现有 Wasp + React + Prisma 的 SaaS 模板上完成两项独立功能:
两项功能均延续既有 ShadCN、Tailwind、后台侧栏、Toast/Dialog 与 Wasp
operations 的工程约定;真正的数据权限在服务端校验,前端限制仅用于体验。
2. 功能一:博客 CMS 后台
2.1 用户能力与路由
/blog/blog/:slug/admin/blog/admin/blog/new/admin/blog/:id/edit/admin/blog/authors/admin/blog/tags2.2 数据关系
erDiagram AUTHOR ||--o{ POST : writes POST }o--o{ TAG : categorised_by AUTHOR { uuid id PK string name string slug UK string bio string avatarUrl } TAG { uuid id PK string name string slug UK } POST { uuid id PK string title string slug UK string excerpt string content string coverImageUrl PostStatus status datetime publishedAt uuid authorId FK }2.3 业务规则
DRAFT、PUBLISHED;发布时写入publishedAt=now(),撤回时清空发布时间。status=PUBLISHED与publishedAt <= now(),因此草稿、撤回文章和未来发布时间均不会泄露。Post、Author、Tag的 slug 各自唯一,格式为 3–120 位小写 ASCII、数字与单连字符:^[a-z0-9]+(?:-[a-z0-9]+)*$。409;删除标签会自动解除文章关联;删除文章要求 UI 二次确认。react-markdown + remark-gfm,不启用原始 HTML,降低 XSS 风险。2.4 权限与错误码
flowchart LR A[请求 CMS operation] --> B{已登录?} B -- 否 --> U[401] B -- 是 --> C{isAdmin?} C -- 否 --> F[403] C -- 是 --> D[校验输入、关系与 slug] D --> E[读写 Prisma 数据] P[公开 Blog 请求] --> Q{已发布且发布时间已到?} Q -- 否 --> N[404] Q -- 是 --> R[返回公开文章]401403409400404这符合 Open SaaS 的约定:客户端权限判断仅改善体验,服务端
context.user与管理员检查才是实际访问控制。Open SaaS 授权指南2.5 管理员操作手册
ADMIN_EMAILS配置识别的账号登录。/blog/<slug>核对公开效果;需要下线时点击 Unpublish。3. 功能二:AI HTML 动画生成与视频渲染
3.1 页面与用户流程
/animations/animations/new/animations/:idsequenceDiagram actor U as 登录用户 participant W as Wasp Web/App participant J as PgBoss 生成任务 participant M as AI Provider participant R as 独立 Renderer participant S as S3/本地存储 U->>W: 提交标题、提示词、时长、idempotencyKey W->>W: 校验输入、所有权与积分预占 W-->>U: 快速返回 GENERATING 记录 W->>J: 投递生成任务 J->>M: 系统提示词 + 用户提示词 M-->>J: JSON { title, html } J->>J: AST/脚本/资源安全校验 J->>W: PREVIEW_READY + 创建 QUEUED render W-->>U: iframe 沙箱预览与播放控制 R->>R: 原子领取任务、租约心跳 R->>R: Playwright 按 30fps 逐帧截图 R->>R: FFmpeg 编码 MP4 + WebM + poster R->>S: 上传文件 R->>W: SUCCEEDED + 文件 key U->>W: 请求下载 URL W-->>U: 私有 S3 签名 URL(15 分钟)3.2 动画效果展示(已验证实例)
本地验收样例使用提示词:
效果要点:深蓝渐变背景、粒子/玻璃球聚合、青蓝色光晕、清晰高对比标题与署名文案。在线预览支持 Pause / Continue / Replay;已验证导出为 1080p、30fps、10 秒 H.264 MP4 与 VP9 WebM。
本地演示入口(运行本项目后可访问):
3.3 生成内容与 AI Provider
AnimationModelProvider抽象隔离业务层与模型 SDK;已实现 OpenAI 与阿里云百炼(Model Studio)适配器。qwen-plus以 JSON 输出 HTML 动画结果;API Key 可由专属工作空间 CSV 安全读取,绝不发送到浏览器或记录到日志。fetch、WebSocket、表单、跳转、iframe、动态导入、存储 API、媒体标签,以及 CSS@import/url(...)。3.4 状态机与可靠性
(userId, idempotencyKey)唯一约束避免重复生成与重复扣费。FOR UPDATE SKIP LOCKED与租约抢占任务;Worker 崩溃、浏览器截图、FFmpeg 或上传失败均可识别并重试,默认最大 3 次。3.5 安全边界
allow-same-origin,父子页面只接受限定的PLAY、PAUSE、RESUME、SEEK、RESTART、GET_STATE消息。userId做所有权校验;匿名401,跨用户记录返回404。local文件存储仅供 localhost 开发/验收:静态文件 URL 不可用于生产访问控制。3.6 渲染与编码规范
1920×1080、30fps,动画最大 10 秒,即最多 300 帧。frame / 30 × 1000ms精确 seek。SUCCEEDED,前端启用下载按钮。libx264yuv420pfaststartlibvpx-vp9yuv420p3.7 操作手册
生成与下载
/animations/new。Generating;任务完成后显示沙箱预览。Queued/Rendering变为Ready、进度 100%。本地启动
本机无 S3 凭据时,在
template/app/.env.server配置:生产环境改用
ANIMATION_STORAGE_DRIVER=s3,并设置 AWS 区域、Bucket、IAM Access Key/Secret;S3 凭据只留在服务端。Open SaaS 推荐采用 S3 签名 URL 保持凭据不暴露给客户端。文件上传指南4. 主要实现位置
template/app/schema.prisma、template/app/migrations/template/app/src/blog/template/app/src/admin/layout/Sidebar.tsx、template/app/src/client/components/NavBar/constants.tstemplate/app/src/animation/template/app/src/animation/provider.ts、aliyunCredentials.ts、generationJob.tstemplate/animation-renderer/template/app/src/file-upload/s3Utils.ts、template/animation-renderer/src/storage.tstemplate/app/docs/blog-cms.md、template/app/docs/ai-html-animation.mdtemplate/e2e-tests/tests/blogCmsTests.spec.ts、animationTests.spec.ts5. 验收与测试
已执行
npx tsc --noEmit。npm run typecheck。npm run lint。npm run prettier:check。git diff --check:通过。qwen-plus请求:成功生成预览。ffprobe验证为 1920×1080、30fps、10.0 秒,MP4 为 H.264,WebM 为 VP9。PR Reviewer 建议验收
/blog。/blog并可通过 slug 打开;撤回后详情 404。6. 部署前检查与后续建议
ADMIN_EMAILS、阿里云/模型 API Key、私有 S3 Bucket 与最小权限 IAM。ANIMATION_STORAGE_DRIVER=local;本地静态下载不能用于生产。7. 推荐 PR 描述结尾