Skip to content

feat(blog): add resilient uploads and virtualized chat - #9

Merged
yororoA merged 6 commits into
mainfrom
feat/blog-resilience
Oct 7, 2026
Merged

yororoA merged 6 commits into
mainfrom
feat/blog-resilience

Conversation

@yororoA

@yororoA yororoA commented Oct 7, 2026 •

Copy link
Copy Markdown
Owner

背景

把博客上传从一次性 multipart 提交升级为可观察、可重试的资产流程,同时降低长聊天记录的渲染成本,并把性能约束纳入 CI。

主要改动

  • article、moment、gallery、chat 接入统一单文件上传队列。
  • 展示逐文件真实传输进度、服务端处理状态、失败原因和单文件重试。
  • moment 增加本地+服务端自动保存、离开页面提醒、稳定幂等键和重复提交锁定。
  • 聊天历史使用 @tanstack/react-virtual 做可变高度虚拟化,保留向上加载锚点与实时消息自动贴底。
  • 增加 JS、首载请求和图片构建预算,并在 GitHub Actions 中执行完整质量检查。
  • 收紧文件选择类型,前端不再接受 SVG;保留 moment/gallery/chat 视频上传。

后端依赖

  • 后端 PR:yororoA/yororoIceBlogBackend#2
  • 部署顺序:先部署后端 PR,再部署本 PR。

验证

  • ESLint、TypeScript、Next.js production build 通过
  • 博客契约回归:19/19 通过
  • 构建预算:JS 251/280 KB gzip,首载请求 21/24,图片总量 9492/12288 KB
  • 桌面及 390×844 移动端浏览器回归通过:无消息重叠、无横向溢出
  • 30 条历史消息场景仅渲染 16 条可视/overscan 行

Summary by Sourcery

Modernize blog media handling with resilient managed uploads, make long chat histories efficient through virtualization, and enforce quality and performance checks in CI.

New Features:

  • Add a unified managed upload workflow for articles, moments, galleries, and chat with per-file progress, processing states, errors, retries, and staged asset handling.
  • Add local and server-side moment draft autosave with navigation warnings and idempotent publishing.
  • Virtualize variable-height chat history while preserving older-message loading and automatic scrolling for new messages.

Bug Fixes:

  • Restrict selectable media to supported raster image and video formats, excluding SVG uploads.

Enhancements:

  • Propagate idempotency keys and support media upload limits and deletion through the blog API proxy.
  • Apply sender-specific chat styling and improve responsive message layout and accessibility.

Build:

  • Add build performance budgets for JavaScript, first-load asset requests, and public images, with automated budget validation.

CI:

  • Add GitHub Actions quality checks covering linting, type checking, production builds, performance budgets, and blog contract verification.

Tests:

  • Extend blog contract fixtures and regression coverage for managed uploads, idempotency, draft media, large chat histories, and upload responses.

@sourcery-ai

sourcery-ai Bot commented Oct 7, 2026

Copy link
Copy Markdown

Sorry @yororoA, you've used your own review budget of 250,000 diff characters for the last 7 days.

You can request another review in 2 days and 12 hours by commenting @sourcery-ai review. Upgrade to get a review now.

@vercel

vercel Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
ark Ready Ready Preview Oct 7, 2026 2:16pm UTC

@sourcery-ai

sourcery-ai Bot commented Oct 7, 2026

Copy link
Copy Markdown

Reviewer's Guide

The PR replaces direct multipart blog uploads with a shared, retryable staged-asset workflow across content and chat surfaces, adds idempotent/autosaved moment drafting, virtualizes long variable-height chat histories, tightens media validation and styling, and enforces the resulting performance and contract requirements in CI.

Sequence diagram for resilient staged media uploads

sequenceDiagram
    participant User
    participant UploadQueue
    participant API as BlogAPI
    participant MediaService
    participant ContentAPI

    User->>UploadQueue: setFiles(files)
    UploadQueue->>API: POST media/upload
    API->>MediaService: POST /api/media/upload
    MediaService-->>API: staged asset
    API-->>UploadQueue: asset and processing status
    UploadQueue-->>User: progress and status
    alt upload fails
        UploadQueue-->>User: error reason
        User->>UploadQueue: retry(uploadKey)
        UploadQueue->>API: POST media/upload with X-Idempotency-Key
    end
    User->>ContentAPI: submit with assetIds
    ContentAPI-->>User: content references staged assets
Loading

Sequence diagram for idempotent moment autosave and publish

sequenceDiagram
    participant User
    participant MomentEditor
    participant BrowserStorage
    participant BlogAPI

    User->>MomentEditor: edit title, content, or media
    MomentEditor->>BrowserStorage: localStorage.setItem
    MomentEditor->>BlogAPI: sendIdempotent(moments/post, draft)
    BlogAPI-->>MomentEditor: saved draft
    MomentEditor-->>User: autosave status
    User->>MomentEditor: publish
    MomentEditor->>BlogAPI: sendIdempotent(moments/post, publishKey)
    BlogAPI-->>MomentEditor: published moment
    MomentEditor-->>User: saved
Loading

Flow diagram for virtualized chat history rendering

flowchart TD
    HistoryAPI[chat/history] --> Messages[Sorted message list]
    Messages --> Virtualizer[useVirtualizer]
    Virtualizer --> VisibleRows[Visible and overscan rows]
    VisibleRows --> Measure[measureMessageElement]
    Measure --> Virtualizer
    Older[Load older] --> HistoryAPI
    NewMessage[Incoming message] --> Stick[Keep latest visible]
    Stick --> VisibleRows
Loading

File-Level Changes

Change Details Files
Introduces a shared staged-media upload pipeline with observable progress and retry behavior.
  • Adds per-file queue state, XHR byte progress, processing status, idempotency keys, concurrency, cleanup, and retry handling.
  • Migrates article, moment, gallery, and chat flows from direct multipart submission to staged asset IDs.
  • Displays per-file status, errors, progress, and constrained image/video selection; excludes SVG.
  • Extends the proxy with media routes, upload timeouts, idempotency forwarding, and a longer execution limit.
src/components/blog/media-upload.ts
src/components/blog/shared.tsx
src/components/blog/articles.tsx
src/components/blog/moments.tsx
src/components/blog/gallery.tsx
src/components/blog/chat.tsx
src/components/blog/blog-provider.tsx
src/app/api/blog/[...path]/route.ts
src/lib/blog.ts
src/components/blog/blog.module.scss
Adds resilient moment drafting and submission safeguards around the new asset model.
  • Persists drafts locally and remotely with debounced autosave, restore support, upload-aware leave warnings, and accessible error focus.
  • Uses stable publish keys and submission locking to make retries and duplicate publishes idempotent.
  • Preserves asset metadata and descriptions when restoring or publishing drafts.
src/components/blog/moments.tsx
src/lib/blog.ts
src/components/blog/blog-provider.ts
Virtualizes chat history while preserving variable-height layout and scrolling behavior.
  • Uses TanStack virtualizer measurement for variable-height rows with overscan and keyed messages.
  • Maintains older-history loading position and automatic scroll-to-bottom behavior for realtime messages/media.
  • Adds deterministic sender styling and responsive spacing updates for virtual rows.
src/components/blog/chat.tsx
src/components/blog/blog.module.scss
src/components/blog/_p3r-ui.scss
src/components/blog/_rain-ui.scss
Adds automated performance budgets and a CI quality gate.
  • Checks route JavaScript size, gzip size, first-load JS/CSS request counts, and public image limits after production build.
  • Runs lint, TypeScript, production build, budget checks, and blog contract verification on pushes and pull requests.
  • Expands contract fixtures to cover staged uploads, idempotency headers, draft/publish metadata, guest upload access, and paginated long chat history.
performance-budgets.json
scripts/check-build-budget.mjs
.github/workflows/quality.yml
package.json
package-lock.json
scripts/verify-blog.mjs

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@yororoA
yororoA merged commit 39aba89 into main Oct 7, 2026
4 checks passed

This branch was successfully deployed

1 active deployment
Preview — d8fea0bc Deployed Oct 7, 2026 by vercel[bot]
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