19 Commits

Author SHA1 Message Date
iye
10878ddb3f feat(vote): 重构投票模型为终身 12 票 + 每艺人 1 票
Some checks failed
Build and Deploy / build-and-deploy (push) Has been cancelled
前端:
- store 改为 votedArtists[] + zustand persist
- VoteModal 删除 1/3/5/ALL 选择器,改三态(待投/已投/满额)
- 卡片/排行/详情页加 hasVoted 状态 + ✓ 角标
- Hero 右上角 Countdown 替换为 HeroVoteProgress(12 格点亮进度)
- /me 改为终身额度叙事(QuotaCard / StatsGrid / MyFanSupport)

后端:
- votes 表加 @@unique([userId, artistId])(已 apply 到生产 RDS)
- /api/vote 重写:12 票上限 + P2002 ALREADY_VOTED + P2003 NOT_FOUND 兜底
- /api/me 新增 votedArtists[] + voteQuota,移除 dailyQuota
- 新增 ERR.ALREADY_VOTED 错误码

测试:
- DB 层 5/5 + E2E 18/18 通过(scripts/e2e-vote-flow.sh)
- 修复 P2003 FK 违反未识别的 bug

详情见 docs/todo/voting-refactor-完成报告.md 与 voting-refactor-backend-完成报告.md

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-15 20:14:57 +08:00
iye
034bb7ff42 chore(ui): drop nav logo + revert hero to default-muted
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 5m30s
- Navigation: removed top-left <Logo />, NavLinks now sit at the
  left edge. Logo component itself kept (still used by Footer /
  LoginForm / LoginModal).
- HeroBanner: restored simple "default muted + autoplay" behavior.
  The earlier try-unmuted-fallback flow was working but produced
  unpredictable first-paint audio depending on browser autoplay
  policy; muted is the safer default.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-15 18:12:21 +08:00
iye
74a7b0ea16 feat(ui): polish hero/logo/cards + bump TOS version + drop missing-video flags
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 4m21s
- Hero eyebrow: "Top 12 · Virtual Idol Debut Project"
  → "Top 12 · Cyber Star Debut Survival"
- Hero video: attempt unmuted autoplay first, fall back to muted on
  browser autoplay-policy block (sound button reflects actual state).
- Logo: replace with cropped v2 art, drop purple drop-shadow glow.
- ArtistCard: drop non-top12 opacity dim AND the top dark gradient
  overlay — new high-quality portraits look better fully exposed.
- mock-data: 003/010/017/027/033 solo videos are present in v2,
  cleared MISSING_VIDEO set so the video section renders for them.
- tos: bump TOS_VERSION to 3 — videos/portraits overwritten on TOS,
  this cache-busts older URLs in browsers and CDNs.

TOS uploads (handled separately): hero-pv.mp4, 5 solo videos
(003/010/017/027/033), 7 cover images, 6/036 atmosphere images.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-15 17:02:29 +08:00
zyc
7168e50a6e fix: prod login + env-file driven config + scroll-snap bounce
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 6m54s
- env: 解封 .env / .env.production 提交, 仅忽略 .env.local 系列;
  .env.production 承载 DATABASE_URL / AUTH_SECRET / AUTH_URL /
  SMS_* / NEXT_PUBLIC_TOS_DOMAIN, Dockerfile runner 阶段 COPY 进
  运行时镜像, Next.js standalone 启动自动加载
- ci: 移除 kubectl 注入 secret 步骤(env 已烧入镜像), 保留占位避免
  envFrom optional 引用告警, 修复 /api/auth/providers 500 (缺 AUTH_SECRET)
- auth: signIn 失败透传 NextAuth 真实错误码, 不再被"验证码错误"一刀切掩盖
- home: 首页 scroll-snap-type 由 mandatory 改 proximity, 修复滚动到
  底部被强制吸回候选区顶部的回弹

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 17:31:00 +08:00
iye
3f5d33c422 fix(ui): merge nav + sticky filter into a single backdrop-filter band
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 7m27s
Two adjacent backdrop-filter elements (nav at y=0-80, filter at y=80+)
always show a visible seam at their boundary because each filter clips
its own blur kernel, so the edge pixels sample slightly different
neighborhoods. Same recipe doesn't help — it's a structural issue.

Fix: when filter is stuck, render an absolutely-positioned glass child
inside the filter that extends from -top-20 to bottom-0 (i.e. covers
nav area + filter area as ONE element). Nav reads filterStuck from a
tiny shared zustand UI store and disables its own glass layer in that
state, so only the shared band is visible. Single element, single
backdrop-filter, no seam.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-14 12:42:03 +08:00
iye
ed222d1c5f feat(ui): scroll-aware nav glass + floating back button + hero polish
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 5m17s
- Navigation: fixed + transparent over Hero (home) / at page top (other routes);
  fades to glass-on-scroll. Glass uses surface tone matching site cards.
- Filter bar sticky glass synced to nav recipe (no seam between layers).
- HeroBanner: full-viewport video, center title removed, bottom dim overlay
  removed, eyebrow/countdown repositioned below the nav.
- ArtistDetail: removed portrait shadow; added FloatingBackButton that uses
  router.back() with internal-history fallback to /.
- Floating buttons (back + vote) translateY upward to avoid footer rather
  than disappearing, via useFooterPush.
- Home: useScrollRestore preserves scroll position on return from detail
  pages; temporarily disables scroll-snap during restore.
- PerformanceVideo: max-w capped by 85svh*16/9 so small viewports never crop.
- ArtistFilters: hide horizontal scrollbar thumb in tag container.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-14 12:25:54 +08:00
iye
71a2672ff6 fix(data,ranking,ui): real dynamic ranking + data sync hardening
数据准确性
- 票数初始为 0,不再用 Math.sqrt 公式造假票
- 排序 tiebreaker 统一为 votes desc + no asc,确保稳定
- store.rank() 与 sortArtists() 行为对齐

Top12 / 出道位
- Top12Bar 仅收纳真正有票的人(votes > 0),0 票时显示"出道位尚未产生"空态
- ArtistCard / RankingRow / SearchModal / MyFanSupport / RankCard 的 inTop12 高亮全部加 votes > 0 守卫
- ArtistFilters 新增"实时排名 / 编号顺序"分段切换 + 首页 sortKey 状态

领奖台 (Top3Podium)
- 1 人有票即可显示领奖台(此前要求 >= 3 人才显示)
- 缺位的 #2/#3 用"虚位以待"占位卡片填充,与正式卡片同 3:4 比例对齐
- 全员 0 票时三张全部显示虚位以待
- 卡片间距拉大到 gap-8 sm:gap-12

排行榜页 (/ranking)
- API 票数与本地乐观投票取 max() 合并,避免 API 落后覆盖本地新票
- 合并后重新排序与赋 rank
- 仅 >= 12 人有票才显示出道线分隔与复活位标记
- 复活位 gapToDebut 计算修正

跨日额度
- selectRemaining 按 quotaDate 判断是否跨日,跨日自动回满额(此前会卡在昨日剩余值)

搜索 (SearchModal)
- 改为订阅 store 拿活的票数,投票后立即反映
- 默认"热门 Top12"只在真正有票时显示,否则降级为"推荐艺人 · 编号顺序"
- 票数显示统一走 formatVotes(0 票不再显示 0.0w)

人物详情
- 36 人真实数据接入,移除全部静态数据(slogan/birthday/cv/themeColor)
- 接入人物小传 docx 数据(年龄/身高/性格/口头禅/技能/赛道/座右铭/长简介)
- 视频区与版心同宽 + 首帧自动作为封面 + 整区点击播放/暂停 + 可拖拽进度条
- 表演图片改为三张氛围图竖向 3:4,左对齐
- 移除分享按钮,投票按钮全宽

个人页 (/me)
- 移除等级/邀请好友/签到/编辑资料等静态数据
- 退出登录按钮在移动端 icon-only 显示(此前 sm:hidden 导致移动端无法登出)
- 我的应援 list 基于真实 myVotesByArtist 派生,凯之类的投票真正同步过去

导航
- 余票徽章未登录态显示 0/0,已登录显示 N/10
- 登录/注册按钮样式与登录后头像胶囊保持一致(紫色实心)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 13:56:42 +08:00
iye
d5ed43acbd feat(ui): design overhaul, global login modal, design spec
- nav: center links (首页/排行榜/我的), right-side AuthMenu + RemainingVotesBadge; image logo with responsive sizing
- auth: replace /login route with global LoginModal triggered anywhere; "我的" intercepts unauth users with post-login redirect
- home: full-screen Hero, redesigned Top12 (12 pill cards, top-3 glow), scroll-snap mandatory between Hero/Top12/candidates
- home: candidates section with sticky filter that gains frosted-glass bg when stuck (matches nav)
- filter: simplified tags (全部/舞蹈/声乐/rap/全能型); ArtistCard uniform purple vote button
- ranking/me: remove Top12Bar; me header stacks 编辑资料/退出登录 vertically
- typography: font-logo set to Orbitron; ✦ glyph in CYBER ✦ STAR preserved
- layout: max-w-[1500px] unified across pages
- docs: add design-spec.md + design-spec.html with full visual spec (lucide SVG, zero emoji policy)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-12 18:59:30 +08:00
iye
bd5a361a18 feat(vote): remove all voting limits (no daily quota, no per-artist cap, unlimited votes) 2026-05-12 14:15:50 +08:00
iye
9fe9fa914f fix(ux): center modals with overlay; live vote with toast; deterministic mock data; cascade layer fix 2026-05-12 14:09:31 +08:00
iye
7949f9bcd1 fix(nav,auth): trim nav to wireframe pages; auth gracefully degrades when DB unavailable in dev 2026-05-12 10:29:02 +08:00
iye
854a162109 feat(live): real-time ranking polling hook + LiveBadge, ranking page falls back to mock when API unavailable 2026-05-12 10:06:16 +08:00
iye
b7fbd5ac53 feat(auth): Auth.js v5 with phone OTP login, send-otp API, login page and user state in nav 2026-05-12 10:03:58 +08:00
iye
4f87a7d36b feat(me): /me user center with quota card, sign-in calendar, stats and fan support 2026-05-12 09:45:47 +08:00
iye
e7166ecf81 feat(ranking): /ranking page with Top3 podium, Top4-12 list, debut line divider and rescue zone 2026-05-12 09:43:41 +08:00
iye
5f06b5122b feat(artist): dynamic /artist/[id] page with hero, 15s video, gallery lightbox, bio and floating vote 2026-05-12 09:42:01 +08:00
iye
28447c2e65 feat(home): add HeroBanner with PV video + ArtistFilters + 35-artist grid/list views 2026-05-12 09:39:21 +08:00
iye
abce95aae8 feat(components): add Button, Countdown, ArtistCard, Top12Bar, VoteModal core components 2026-05-12 09:37:23 +08:00
iye
c441ed7026 feat(layout): add Navigation, Footer and Logo components with root layout shell 2026-05-12 09:32:46 +08:00