Conversation
Move SPEND_OPTIONS array from card-ranking-table.tsx into lib/spend-options.ts so it can be reused by the upcoming RecommendationFinder component. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Client component with page and compact widget modes. Supports: - Intent chip picker + spend selector → live rankCards() results - URL params (?intent=&spend=) sync on full page - localStorage persistence (ow-rec-prefs) - "Doanh nghiệp" tab shows coming-soon state Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Dedicated recommendation page: SSR fetches cards/banks/intents, renders RecommendationFinder full layout. Includes JSON-LD WebPage and BreadcrumbList. Auto-added to sitemap via filesystem scanner. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fetch getIntents() alongside existing cards/banks, render
RecommendationFinder compact limit={3} widget below the hero section.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
useCompareList() hook backed by localStorage (key: compare_list, max 3). Same useSyncExternalStore pattern as use-recent-compares.ts. API: compareList, addToCompare, removeFromCompare, toggleCompare, clearCompare, isInCompare, isFull. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fixed bottom bar, z-50, slides up when ≥1 card in compare list. Shows count, "So sánh ngay" button (enabled at ≥2), and "Xóa" link. Navigates to /so-sanh/id1-vs-id2[-vs-id3]. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Third circle button (IconScale) in hover overlay. Active state when card is in compare list, disabled when list full and card not in list. Calls toggleCompare on click with propagation stopped. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove useSearchParams(), lastProcessedParam/lastSynced refs, and both URL-sync effects. Add usePathname-aware navigation: when ≥2 cards selected, push to /so-sanh/id1-vs-id2 (or replace if already on a pair page). Prefill uses defaultPair → recent compares → defaults. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
/so-sanh?compare=id1,id2 now redirects server-side to /so-sanh/id1-vs-id2. Preserves old shareable URLs while moving to the canonical pair URL format. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- store card name + image_url in compare_list_meta (localStorage) - addToCompare/toggleCompare accept optional meta; fire sonner toast on add - CompareBar desktop: 3 slots with thumbnail, name, × remove button - CompareBar mobile: count-only compact mode - new CompareButton for card detail page (3 states: add/active/full) - card-tile passes name+image_url to toggleCompare so bar shows correct data - mount Toaster in marketing layout above CompareBar
…ankedRow - Replace single intentSlug with intentSlugs[] for multi-select chips - Red banner, tab toggle (Cá nhân / Doanh nghiệp), unified layout - Spend selector uses chevron + Select pattern from card-ranking-table - URL sync gated on /goi-y-the pathname to prevent homepage redirect - Export RankedRow from card-ranking-table; use it in right panel for tiebreaker indicators and rank badges - Remove compact prop and CompactResultRow
Add @assistant-ui/react, @assistant-ui/react-ai-sdk, @ai-sdk/groq, ai, zod. Generate thread.tsx and 11 sibling components via assistant-ui CLI. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Restricts assistant to Vietnamese card topics only; includes refusal template for out-of-scope questions. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Tools: searchCards, getCardDetail, rankCardsForSpend, compareCards, listBanks. All tools use apiFetch(); rankCardsForSpend delegates to rankCards(). IP-based rate limit: 20 req/min, 429 with Vietnamese error message. History trimmed to last 12 messages before streamText call. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ChatPageClient: useChatRuntime + AssistantChatTransport, localStorage sync debounced 500ms via onFinish callback. ChatPage: metadata, ow-chat-page wrapper, renders client component. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Covers: happy path (banks, cashback recommendation, compare, fee inquiry), out-of-scope (gold price, stock market), vague query, hallucination guard. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
AI SDK v6 sends UIMessage[] (with parts/metadata/id) from the client; streamText expects ModelMessage[]. Use convertToModelMessages() to bridge. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Documents gotchas: UIMessage vs ModelMessage, tool() API change, maxSteps removal, streaming method rename, useChatRuntime transport. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Move /chat from (marketing) to (chat) route group — bare layout, no header/footer - Add multi-conversation localStorage store (lib/chat/conversation-store.ts) with legacy migration from ow-chat-history - Rewrite chat-page-client: shadcn Sidebar + conversation list grouped by date, new/delete per convo, key-based runtime remount on switch - Fix hydration mismatch: defer localStorage reads to useEffect, init state empty on server - Add OpenWallet logo + home link to sidebar header - Remove attachment UI from thread composer (text-only input) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace split-view right panel with floating bottom-right widget. Desktop: 380×560 popup; mobile: full-screen. ⌘/ shortcut to toggle. Chat toggle button restyled to match search trigger (border + icon + text). No more layout content shifting — ChatLayoutWrapper removed. Card/bank detail pages inject current page into AI system prompt via ChatContextSetter + buildSystemPrompt, so AI knows what user is viewing. Context hint badge shown above composer when active. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Logo accepts href prop (string | null); null renders span instead of Link - Chat panel logo links to /chat - Maximize button closes panel and navigates to /chat?id=<activeId> Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace TOP 1/2/3 text badges with laurel wreath icons - Tiebreaker reason: shorten fee copy, swap pill badge for bulb icon - Wrap spend changes in startViewTransition for smooth card reorder
- Rename /so-sanh → /card-battle, /goi-y-the → /card-match - Add lib/tools.ts as single source of truth for all 4 tool hrefs - Add 301 redirects for old routes to preserve SEO equity - Add "Công cụ" hover dropdown in desktop nav, collapsible in mobile nav - Update footer to derive tools list from lib/tools.ts - Replace all hardcoded tool hrefs across 12+ files with getTool() imports Tools: Card Battle, Card Match, Wallet Chat, Wallet MCP
Wire /api/chat to consume tools from MCP server via @ai-sdk/mcp instead of inline tool definitions. Add scripts/mcp-status.ts for terminal health monitoring of MCP and API services during dev. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- apiFetch: warn on missing OPENWALLET_API_KEY per request - apiFetch: specific 401/403 messages instead of generic "API error" - apiFetch: detect 200+HTML responses (CDN/WAF) and throw with URL hint - the/[slug] + ngan-hang/[slug]: wrap generateStaticParams in try/catch - sitemap: wrap bank/card fetches in try/catch, degrade gracefully Category pages (the/, the-shopee/, etc.) intentionally hard-fail so build stops with the new clear error message instead of SyntaxError. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
API server ALLOWED_ORIGINS check requires Origin header. Server-side fetch() sends none → 403. Hardcode openwallet.vn. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Wrap MCP init and streamText in try/catch with console.error - Return JSON 500 response on fatal error instead of unhandled throw - Add onError to useChatRuntime: logs to console + shows red banner in UI Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…auses stream death Tool choice conflict: SDK sets tool_choice=none after step 1, model ignores it, Groq rejects → stream dies with no answer. Removed tools + stopWhen until a compatible model or workaround is found. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Migrate 8 test cases from inline array to evals/cases/*.json - Add LLM judge (Groq json_object mode) with score + reasoning - Write JSONL per run, push to openwalletvn/evals via GitHub API - Add evals/server.ts (port 3006, trigger endpoint) - Add evals/ui/ — Vite+React UI with RunList, RunDetail, PromptCompare - Add evals/wrangler.toml for Cloudflare Pages deploy - Add .github/workflows/eval-run.yml and evals-site.yml - pnpm evals → single port 3005, /server proxy to backend Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Fix CWD bug in server.ts (parent of web/ → web/) - Add SSE streaming: POST trigger returns runId, GET stream/:runId pipes stdout in real-time via EventEmitter fan-out - Add triggered_by (ui/cli/ci) and system_prompt fields to EvalResult - UI: two-column layout, dark terminal progress panel, card-based run list with tag summary and trigger badge, run detail with full system prompt + expandable AI responses + judge/rule disagreement flag - Rewrite 13 eval cases with realistic Vietnamese queries: shopee+supermarket cashback, no annual fee, travel abroad, installment 0%, hallucination guards for fabricated rates, out-of-scope: gold/stocks/real estate - Add .claude/docs/evals.md maintenance documentation Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Single case selector: dropdown grouped by tag, runs just one case - Push to GitHub checkbox: skip polluting results with WIP runs - Delete run: button per card proxies GitHub Contents API delete - Re-run failures: button appears when selected run has failing cases - Live progress: SSE streaming with current case name + N/M counter - System prompt per run: expandable with GitHub blob link at that SHA - Trigger source tracking: ui/cli/ci badge on each run card - Score trend arrow vs previous run, disagreement flag (rule vs judge) - Copy button on AI response, inline re-run per test case card - Relative timestamps with absolute on hover, descriptive button labels Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…X features Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…p in footer - Remove RCGV and Perxel mentions from ve-openwallet and chinh-sach-bao-mat - Remove "chia sẻ miễn phí" claim (MCP/Chat will be paid features) - Generalize tool-specific names in legal pages (future-proof) - Create /lien-he contact page, consolidate all email refs there - Add Liên hệ link to footer categories - Mark Wallet App disabled in footer; Wallet Chat/MCP keep landing page links - Replace WalletAI reference with Wallet Chat in dieu-khoan Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
feat(evals): eval system with LLM judge, JSONL push, and React UI
content: remove RCGV/Perxel, add contact page, footer cleanup
…eview All WIP feature CTAs (MCP, Wallet Chat) now route to /lien-he instead of direct mailto links. Contact page replaced with interactive ContactForm: topic picker, mail preview UI, single mailto button as the one exit point. Also fixes h3 Tailwind typography override in wallet-chat and tightens layout.md to ban Tailwind size/weight utilities on heading elements. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add .text-link to typography.css as single source for prose link style - Replace inline [&_a]: chains and hardcoded colors across all marketing pages - Document rule in layout.md: multi-property patterns belong in typography.css - Rewrite MCP page: why-we-built framing, remove beta key/config sections, add inspector.openwallet.vn and wallet-chat references - Fix incorrect origin story (card directory, not comparison app)
Rewrote changelog.mdx with 12 entries covering Feb 16 to May 24, telling the full build story for both end users and developer/AI engineer audience. Added .claude/docs/changelog.md with purpose, rules, format guide and LLM verification checklist. Updated CLAUDE.md to reference the new doc. Also includes local font migration for Cal Sans (latin + latin-ext + vietnamese subsets) to avoid Google Fonts dependency. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Chat feature not ready for public. Remove ChatToggleButton from header (desktop + mobile). Block /app from crawlers via robots.txt.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
next/font/local does not support unicodeRange per-src. Drop range hints — all three Cal Sans subset files still loaded.
Fetches live version from /health endpoint (ISR 1h) so the MCP page shows the real version instead of a hardcoded badge. Self-contained, zero props — reusable anywhere in the app.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
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.
Summary
Test plan
🤖 Generated with Claude Code