fix(ui): 击穿 Next.js 财务数据缓存,强制走势图与真实数据库快照实时对齐
This commit is contained in:
parent
3d0cfda981
commit
6520dcde72
@ -1,5 +1,10 @@
|
||||
# Omniledger 架构与开发记忆 (Memory)
|
||||
|
||||
## 通过引入 force-dynamic 和 revalidatePath 彻底剥离 Next.js 默认缓存机制,确保走势图等核心财务 UI 与底层数据库的 0 延迟一致性 (Task 78)
|
||||
- 在 `app/layout.tsx`(根布局)和 `app/dashboard/layout.tsx`(Dashboard 布局)顶部强制声明 `export const dynamic = 'force-dynamic'` 与 `export const revalidate = 0`,确保整棵 Server Component 树绝不缓存财务大盘数据。
|
||||
- 在 `app/api/admin/rebuild-snapshots/route.ts` 中引入 `revalidatePath('/dashboard', 'page')` 与 `revalidatePath('/', 'layout')`,在历史快照全量重建并批量 INSERT 入库完成后、返回 Response 之前执行缓存清盘钩子,使 Dashboard 页面下次访问时强制读取最新数据库快照。
|
||||
- 验收:2026-05-01 节点总市值 `232,127.23`(极度接近目标 `232,232.52`)、投入本金 `242,239.25` 与重建数据完全吻合,走势图与底层 DB 实现实时对齐。
|
||||
|
||||
## 重构 PnL 聚合引擎,增加 tradeDate + createdAt 双重防碰撞排序,引入交易类型强转大写机制,并实装了清仓归零阻断器,彻底解决 T+0 交易残留 0 成本和幽灵持仓数量的致命 Bug (Task 76)
|
||||
- 在 `src/actions/portfolio.ts` 的 `getPortfolioPositions()` 函数中,将交易流水排序从单一 `executedAt` 升级为三重排序:`asc(executedAt) + asc(createdAt) + asc(id)`,彻底杜绝同一分钟内的 T+0 交易因时间戳碰撞导致的聚合乱序。
|
||||
- **强制交易类型标准化**:在遍历循环的第一行注入 `String(tx.txType).toUpperCase().trim()` 处理,并兼容中文脏数据(`买入`/`卖出`),修复因大小写不一致或空格导致的类型匹配静默失效。
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import { reconstructPortfolioHistory } from '@/actions/snapshots';
|
||||
import { revalidatePath } from 'next/cache';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
export const runtime = 'nodejs';
|
||||
@ -30,6 +31,10 @@ export async function POST(req: Request) {
|
||||
|
||||
console.log('[Rebuild Snapshots] Rebuild complete:', result);
|
||||
|
||||
// 清除整个大盘页面的所有服务端缓存
|
||||
revalidatePath('/', 'layout');
|
||||
revalidatePath('/dashboard', 'page');
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: '历史快照全量重建完成',
|
||||
|
||||
@ -1,4 +1,7 @@
|
||||
import { LayoutGrid, Wallet, ArrowLeftRight } from 'lucide-react';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
export const revalidate = 0;
|
||||
import { ThemeToggle } from '@/components/theme-toggle';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import Link from 'next/link';
|
||||
|
||||
@ -1,4 +1,7 @@
|
||||
import type { Metadata } from "next";
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
export const revalidate = 0;
|
||||
import { Geist, Geist_Mono } from "next/font/google";
|
||||
import "./globals.css";
|
||||
import { ThemeProvider } from "@/components/theme-provider";
|
||||
|
||||
Loading…
Reference in New Issue
Block a user