update
Some checks failed
deploy / deploy (push) Has been cancelled

This commit is contained in:
toom1996
2026-08-26 19:42:10 +08:00
parent d64a046f82
commit eee2265e15
29 changed files with 337 additions and 2506 deletions

View File

@ -1,58 +1,37 @@
# 项目长期记忆(Project MEMORY.md)
## 模块策略(重要)
- 站点按模块逐个完善。当前只上线「发布会模块」:首页 index + 品牌索引 brands + 走秀列表 articles + 走秀详情 article。
- **所有走秀页 `/shows`**(新建 2026-08-08):全局走秀档案(区别于 `/articles` 的品牌档案视图 ?brand_id)。基于 articles.astro,标题「All Runway」,保留系列/季节/品牌筛选 + 三视图(Grid/Magazine/Timeline),新增分页 Load More(page/total/busy,append 模式,后端 `?page=&size=30&with_images=5`)。首页 sec-more「全部走秀 →」指向 /shows。
- 其余模块(Portfolio / Latest Projects / About / Contact / 登录注册)为「暂未上线」占位页:直接访问旧 URL 或点击导航旧链接均渲染 ComingSoon 占位;**导航(header)保持原样未改动**(用户 2026-08-07 明确「header 别动」),门禁完全靠占位页实现。
- **首页 tabbar**(index.astro, id="tabbar"):仅「发布会(backstage)」上线(默认激活 + Live 徽标,承载 getShows(8) SSR 真实卡片);「灵感(shows)/社媒(events)/街拍(street)」标 `data-soon="true"` + Soon 灰徽标,点击仅显示 ComingSoon 占位、不再请求后端;「品牌」tab 仍为指向 /brands 的有效链接(属已上线模块,未屏蔽)。
- 占位实现:src/components/ComingSoon.astro(编辑风,props: module / moduleZh / note;两个按钮「浏览走秀档案 →」「返回首页」)。portfolio / latest-projects / about / contact 仍为 ComingSoon 占位页。
- **登录/注册(2026-08-25 更新)**:`/en/login`、`/en/register` 已做成真实编辑风页面(套 Layout + 新建 `src/components/pages/AuthForm.astro` 通用表单组件,`mode:'login'|'register'`,客户端 POST `/api/auth/login|register`,用 `saveSession` 写 `fa_token`/`fa_user`)。根 `/login`(src/pages/login.astro) 与 `/cn/login` 等**仍是 ComingSoon 占位**(未动,属当时范围外);导航 Login/Signup 在 en 语境下现指向真实的 /en/login、/en/register。
- 站点按模块逐个完善。当前上线「发布会模块」:首页 index + 走秀列表/详情(RunwayLooks = 走秀档案页,articles/shows 页面已在 i18n 重构中重组)。
- **品牌索引页已下线**(2026-08-26 确认):`src/pages/brands.astro` 及孤儿组件 `src/components/pages/brands.astro` 均已删除;品牌数据现在只通过走秀页侧栏 filter + 品牌弹窗呈现(热门 30 条走 SSG 接口,搜索/字母走运行时 `/api/v1/public/brands`)。
- 其余模块(Portfolio / Latest Projects / About / Contact / 根路径登录注册)为 ComingSoon 占位页;**导航(header)保持原样未改动**(用户 2026-08-07 明确「header 别动」),门禁完全靠占位页实现。`/en/login`、`/en/register` 已是真实页面(`AuthForm.astro`,mode login/register)。
## 架构总览
- 前端:/d/project/test/test — Astro SSG + Tailwind v4。构建 `PUBLIC_API_BASE=http://localhost:8090 npm run build`;预览 `python -m http.server` 托管 dist/。
- 后端:/d/project/admin/backend — Go + Gin + GORM(MySQL),:8090。路由分后台 /api/* 与公开只读 /api/public/*。
- 数据层:前端 src/lib/data.ts 统一从 /api/public/* 拉数据;后端不可达时回落内置示例。
- 前端:**d:/project/frontend_v2** — Astro SSG + Tailwind v4 + Alpine.js。`npm run build`(SSG 取数走 ssgRequest,失败回落空/假数据不影响构建)。
- 后端:**d:/project/backend_v2** — Go + Gin + GORM(MySQL),公开引擎 :8090(`/api/v1/public/*`、`/api/v1/auth/*`),SSG 内部引擎 :8091(仅 127.0.0.1,`/api/v1/ssg/*`,SSGToken 中间件,nginx 不反代)。
- **SSG 分组现状(2026-08-26)**:只剩两个端点——`/api/v1/ssg/index/runway`(首页 runway 区块,`IndexService.Runway`,hotBrand 20 条)+ `/api/v1/ssg/brands/hot`(走秀页热门品牌,`BrandService.Hot`,固定 30 条、按图片总数热度顺序,零参数)。`/ssg/brands`(全量 A-Z)与 `/ssg/articles/ids` 均已删除。
- **接口 i18n 约定**:后端按 `?locale=cn|en` 选列返回(pickLocale 缺翻译回落另一语言);前端取数统一复用带 locale 的原语(request/ssgRequest 等),**绝不裸写 fetch;语言以 URL 前缀为准**。
- 走秀标题 `title_cn` 已规则回填(backend_v2 `scripts/backfill_title_cn/main.go`,幂等);`description_cn` 为空白属预期,中文页回落英文。
## 关键约定
- 视觉语言:黑白极简编辑风(monospace + Georgia 衬线大标题 + 细线),HBX / 时尚档案调性。
- 字体:全站走 Tailwind 体系(font-sans / font-mono / font-serif),禁止自写截断字体栈。新增页面复用项目字体变量。
- CSS 写法:能用 @apply 就 @apply;`<style>` 顶部加 `@reference "tailwindcss";`。仅保留手写:@keyframes、渐变 shimmer、!important、双时长 transition。Tailwind v4 已移除零值类(mt-0 等),零值边距保持手写。
- 导航(Layout.astro):**保持原样未改动**(Portfolio / Latest Projects / About / Contact / Login / Signup),含页脚 Categories + Color Studio Tools + About/Contact 链接。门禁仅由 6 个 ComingSoon 占位页承担,导航不删任何链接(用户要求 header 别动)。
- 视觉语言:黑白极简编辑风(monospace + Georgia 衬线大标题 + 细线),HBX / 时尚档案调性。字体全走 Tailwind 体系,禁止自写字体栈。
- **品牌名前端一律只显示英文**(用户偏好 2026-08-26:「前端品牌不要展示中文名称,标题可以留着」):api.ts 映射 `display = nameEn`;走秀标题/描述仍按 locale 选列。
- **API 命名哲学(用户原则)**:「每一个地方尽可能不要通过参数来复用接口,尽量一个功能一个接口」。查询参数仅限「同一资源的列表筛选/分页」;跨资源/独立功能一律独立路径(如 `brands/hot` 而非 `?featured=1`)。待办:公开侧 `/api/v1/public/brands` 的 featured/keyword/letter 参数拆分、`/articles` 的 `brand_id` 拆 `brands/:id/shows`、资源命名 `shows` vs `articles`、`popular` vs `featured`(目标清单见 artifact `api_endpoints_catalog.md`)。
- CSS:能 @apply 就 @apply;`<style>` 顶部 `@reference "tailwindcss";`。Tailwind v4 无零值类。
- 导航(Layout.astro)保持原样,门禁仅由占位页承担。
## Layout 陷阱(重要,2026-08-12 踩坑)
- **Layout.astro** 把 `<slot />` 包裹在 `<div class="flex-1 flex flex-col">`(flex column 容器)。
- **禁用 `m-auto`** 作为页内根容器(`<div class="xxx m-auto">`):它在 flex column 容器中作为 flex item 的 cross-axis `margin: auto`,会触发 **shrink-to-fit**(content 决定宽度),导致:
- 内容空/少时根容器收缩到极窄(骨架 24 张空 div → .showsroot 仅 626px / 主区 350px / 卡片 164px)。
- 内容多时根容器被撑大(真实卡片有 img/文字 → 1042px 「看起来正常」)。
- 同页面在不同内容状态下宽度剧烈变化 = 抖动。
- **正确做法**:用 `w-full`(强制 100% 父容器,常配 `max-w-[xxx]`),或 `w-full mx-auto`(保留大屏居中)。
- 适用范围:所有 Layout 内的页内根容器(包括 showsroot / blogs / about 等),**避免 `m-auto` 单独使用**。
## Layout 陷阱(2026-08-12)
- Layout 把 `<slot />` 包在 `flex-1 flex flex-col` 容器里;页内根容器**禁用 `m-auto`**(cross-axis margin:auto 触发 shrink-to-fit → 内容多少决定宽度、页面抖动)。用 `w-full`(可配 `max-w-[xxx]` + `mx-auto`)。
## Astro frontmatter 与 `<script>` 作用域隔离(通用坑)
- **frontmatter 里的 `import` / 变量,在 `<script>`(客户端打包脚本)里拿不到**。两者是分别打包的:frontmatter 是服务端渲染期,`<script>` 是独立客户端 bundle。脚本里直接用 frontmatter 引的 `ROUTES` / `clientHref` 等,esbuild 不报错(当全局变量),但 **TS 语言服务报 `ts(2304) 找不到名称`**,运行时更是 `ReferenceError`。
- **正确做法**:脚本里要用什么,就在该 `<script>` 顶部重新 `import`。例:`import { clientHref, ROUTES } from "@/lib/routes"`。
- 排查方法:在 `<script>` 块里 `import` 行 grep,确认用到的标识符都已在脚本作用域内 import。本仓库曾在 RunwayLooks.astro、pages/shows.astro、pages/cn/shows.astro 三处脚本用了 `clientHref`/`ROUTES` 却只在 frontmatter import,统一补 import 修复(2026-08-24)。
## Astro `<script>` 两大坑
- **作用域隔离**:frontmatter 的 import/变量在打包型 `<script>` 里拿不到(运行时 ReferenceError);脚本里要用什么就在脚本顶部重新 import。
- **不做模板插值**:打包型 `<script>` 里 `{t('...')}` 不会被执行 → `t is not defined`。预翻译用 `define:vars={{ hiLabel }}` 注入;模板区 `{t()}` 正常。
- 打包后脚本在 `_astro/*.js` 而非内联;查 dist 产物用 search_content(ripgrep),PowerShell 无 `Select-String -Recurse`。
## i18n 脚本内翻译陷阱(2026-08-23 踩坑)
- **Astro 对「打包型 `<script>`(module)不做 `{...}` 模板插值**。若在前端 `<script>` 里写 `slot.innerHTML = \`...{t('Hi')}...\``,构建后 `t('Hi')` 会原样留存在打包 JS 中 → 运行时 `t is not defined` 报错、脚本中断。
- **正确做法**:在 frontmatter 用 `const hiLabel = t('Hi')` 预翻译,再用 `<script define:vars={{ hiLabel, logoutLabel }}>` 把字符串注入脚本,脚本内用 `${hiLabel}` 引用。define:vars 会把 `const hiLabel="..."` 注入到该 page 的脚本作用域(en 得英文、cn 得中文)。
- 模板(`<template>` HTML 区,非 `<script>`)里的 `{t('...')}` 插值正常可用,仅 `<script>` 受限。
- 验证坑:`Select-String -Recurse` 在 PowerShell 不存在(参数名不符);查 dist 产物改用 ripgrep 工具(search_content,递归默认开启)或 `Get-ChildItem -Recurse | Select-String`。
- 注意:打包后 `<script>` 内容不在 HTML 内联,而在 `_astro/*.js`;用 `--` 类 UX 标志(如 `activeThemePalette` 控制的 Reset B&W Theme)在对应 prop 为空时不会渲染,静态 HTML 搜不到属正常。
## 走秀数据分类(brand_runway)
- 三维分类字段:`collection_type`(rtw/menswear/couture/resort/pre_fall)、`season`(spring/fall/null)、`season_code`(SS26/FW25…派生)。靠 title 规则回填(幂等,25,206 行)。
- 公开列表 `?collection_type=&season=&season_code=&year=` 筛选;前端走秀页有系列/季节/年份 chips。
- 地理/城市维度:用户明确暂不做。
- 分布:rtw 15203 / menswear 4061 / couture 672 / resort 2894 / pre_fall 2376。
## 部署(Docker + Gitea Actions)
- 仅 brands.astro 构建期 SSR 取数(用 API_SSR);其余页面运行时相对 /api 拉取(nginx 反代 backend:8090)。
- 交付文件:前端 Dockerfile / nginx.conf / docker-compose.yml / deploy.sh / .gitea/workflows/deploy.yml / .env.example / DEPLOY.md;后端 Dockerfile。
## 走秀数据分类(brand_runway,已实现 2026-08-08)
- **三维分类字段**(已加,靠 title 解析回填,无需外部数据):
- `collection_type`:rtw / menswear / couture / resort / pre_fall
- `season`:spring / fall / null(Resort/Pre-Fall 为单季,season=null)
- `season_code`:SS26 / FW25 / RES26 / PF25(派生,用于排序/展示)
- **回填**:main.go `backfillRunwayClassification()` 单条 `UPDATE ... CASE` 解析 title(Vogue 格式 `Spring/Fall 2016 Ready-to-Wear`、`Pre-Fall 2016`、`Resort 2017`、`Fall 2016 Couture`、`Spring 2005 Menswear`),仅处理 `collection_type=''` 行(幂等)。实测 25,206 行 ~338ms 完成。
- **接口筛选**:`GET /api/public/articles` 新增 `?collection_type=&season=&season_code=&year=`,响应含三字段。
- **前端筛选**:articles.astro 增加「系列类型 / 季节」两组 chips(`#typefilter` / `#seasonfilter`),点击经 `loadBackend()` 带参重拉。
- **首页 feat 改竖版编辑拼图**(index.astro, 2026-08-08):原 4:3 横图 hero 改为「左侧大竖图(feat-main, aspect 3/4) + 右侧 3 张竖版 rail(feat-rail-item, grid-rows-3)」,**用同一场秀自己的 gallery(最多5张)做多图拼图**(避免横图裁切竖版),保留系列/季节 chip(feat-fill 渐变浮层)。`feat` 整块带 `data-ct` 供系列筛选隐藏。
- **首页「查看更多」内联加载**(index.astro, 2026-08-08):网格下加 `#showmore` 按钮,JS 分页 `fetch ?page=2..&size=8&with_images=5` 追加到 `#showgrid`,带 `homeFType` 系列筛选参数;无更多显示「没有更多了」。系列筛选 IIFE 重构为 `seriesApply()` 暴露 `homeFType`。
- **地理/城市维度:用户明确暂不做**(爬 Vogue 页不可靠;城市方案后续可用「品牌→所属时装周城市」映射表,Resort/Pre-Fall 归巡演桶)。
- 分布实测:rtw 15203 / menswear 4061 / couture 672 / resort 2894 / pre_fall 2376;spring 9140 / fall 9049。
- 交付文件:前端 Dockerfile / nginx.conf / docker-compose.yml / deploy.sh / .gitea/workflows/deploy.yml / .env.example / DEPLOY.md;后端 Dockerfile。nginx 拦截 `/api/v1/ssg/` 404;健康检查 `/api/v1/public/brands`。