Files
yeuimu 6c61a4e871 feat(deploy): production deployment setup and fixes
- Debian-based api image (bookworm-slim), docker/debian mirrors, prisma
  binaryTargets for openssl 3.0
- nginx: admin SPA under /admin, TLS via acme.sh (ZeroSSL) + auto-renewal
  cron, http->https redirect
- prisma: add origin_goods.delisted migration, sync missing schema
  (good_image/tag_font_color/good_tags), fix users.createdAt Timestamptz
- api: CORS wildcard reflection, helmet CORP cross-origin, price
  backfill in persistProductDetail, categoryIcon ancestor fallback,
  mediaByColor per-color gallery in public goods detail
- admin: /admin base path (vite + router)
- import-data.mjs: udt_name casting, serial sequence advance fix
2026-08-26 14:23:09 +08:00

194 lines
6.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# AGENTS.md - AI Agent 开发规范
## 项目概述
InkReach 官网项目,基于 Nuxt 4 + Vue 3 + Tailwind CSS v4 的静态展示站点。
## 开发流程
- 包管理器:`npm`
- TypeScript strict 模式,所有代码必须通过类型检查
- 页面与组件代码放在 `app/` 目录下,符合 Nuxt 约定
### 1. 梳理需求
开发前确定好需求类型,在对应的 `plans/` 子目录下创建计划文档:
| 需求类型 | 计划目录 | 命名规则 | 示例 |
| -------- | ----------------- | --------------------- | ----------------------- |
| 新功能 | `plans/feature/` | `xxx-xxx-feature.md` | `hero-banner-feature.md` |
| 修 Bug | `plans/fix/` | `xxx-xxx-fix.md` | `layout-overflow-fix.md` |
| 重构 | `plans/refactor/` | `xxx-xxx-refactor.md` | `component-split-refactor.md` |
计划文档最末尾是开发任务表,每个任务项都有一个对应的二级标题的任务详情描述;当需求完成时任务项也标记勾选了。
### 2. 建立开发分支
使用 `enterprise-git-spec` 技能来建立分支。分支命名:
- 新功能:`feature/xxx-xxx`
- 修 Bug`bugfix/xxx-xxx`
- 重构:`refactor/xxx-xxx`
### 3. 按照需求开发
按照计划文档的任务项逐步实现功能。
**重要原则:所有测试必须通过**
- 开发过程中,确保所有测试用例通过
- 如果发现现有测试失败,必须立即修复
- 只有在所有测试都通过的情况下,才能认为开发完成
### 4. 合并到开发分支
所有测试通过后,使用 `enterprise-git-spec` 技能提交分支,然后合并回 `develop` 分支。
### 5. 沉淀开发经验
实现功能过程中,将通用的编码好想法、好思想、注意点等及时追加到本文件中。
### 6. 更新项目结构文档
每次功能开发完成后,更新 `docs/references/structs.md` 文件,记录项目目录结构和模块功能描述。
### 7. 更新使用文档
1. `README.md` - 快速上手,新功能开发完成后更新
2. `docs/references/*` - 详细使用指南,每次功能变更后更新
3. `skills/inkreach-official-website/SKILL.md` - AI Agent 使用文档
## 技术栈
| 技术 | 版本 | 用途 |
| --------------- | ----- | -------------- |
| Nuxt | 4.x | SSR/SSG 框架 |
| Vue | 3.x | UI 框架 |
| Tailwind CSS | 4.x | 原子化 CSS |
| @nuxtjs/seo | 5.x | SEO 模块 |
| FontAwesome | 7.x | 图标库 |
## 开发规范
### Vue / Nuxt 规范
- 使用 `<script setup>` + Composition API + TypeScript
- 组件文件命名:PascalCase(如 `ProductCard.vue`
- 页面放在 `app/pages/`,组件放在 `app/components/`
- 布局放在 `app/layouts/`
- 使用 Nuxt 自动导入,无需手动 import 组件和 composables
### 代码风格
- 缩进:2 空格
- 分号:必须
- 引号:单引号
- 行宽:100 字符
- 末尾逗号:es5
### TypeScript 规范
- 所有函数必须声明参数和返回值类型
- 优先使用 `interface`,交叉类型时用 `type`
- 避免使用 `any`,必须使用时用 `unknown` 替代
### Tailwind CSS 规范
- 自定义主题颜色在 `app/assets/css/tailwind.css``@theme` 中定义
- 自定义动画也在 `@theme` 中通过 `--animate-*``@keyframes` 注册
- 优先使用 Tailwind 工具类,必要时使用 `@apply``[任意值]` 语法
### 现有主题色
| 变量名 | 色值 | 用途 |
| --------------------------- | -------- | ------------ |
| `--color-primary` | `#fd6a03` | 主色调 |
| `--color-inkreach-homepage-1` | `#f3f4f5` | 浅灰背景 |
| `--color-inkreach-homepage-2` | `#f8f9fb` | 次浅灰背景 |
| `--color-inkreach-homepage-3` | `#fff6f0` | 暖色浅背景 |
| `--color-inkreach-homepage-4` | `#FF6800` | 橙色强调 |
| `--color-inkreach-homepage-5` | `#0C0501` | 深色/页脚 |
### 常用命令
```bash
npm run dev # 开发模式(nuxt dev --host
npm run build # 构建(nuxt build
npm run generate # 静态站点生成(nuxt generate
npm run preview # 预览构建产物
```
## 经验沉淀
### 启用 Nuxt 文件式路由
项目原先用 `app/app.vue` 作为整页入口。要新增独立路由页(如 `/product-center`):
1.`app/app.vue` 现有内容迁移到 `app/pages/index.vue`(保持 `/` 渲染原首页)。
2.`app/app.vue` 替换为最小容器:
```vue
<template>
<NuxtPage />
</template>
```
3. 新建 `app/pages/<name>.vue` 即可通过 `/<name>` 访问。
### Nitro 后端代理模式
若要把外部 HTTP API(如 NestJS 后端)包装为同源 `/api/*` 路由:
```typescript
// server/api/backend/categories.get.ts
export default defineCachedEventHandler(
async (event) => {
const config = useRuntimeConfig();
return $fetch(`${config.public.backendUrl}/public/categories`);
},
{
maxAge: 60,
swr: true,
name: 'backend-categories',
getKey: () => 'tree',
},
);
```
`runtimeConfig.public.backendUrl` 通过 `.env` 的 `NUXT_PUBLIC_BACKEND_URL` 注入,可被前端直接 `$fetch('/api/backend/...')` 调用且保持 SSR 工作。
注意:带 query 的列表接口(如 goods)需在 `getKey` 中将 `getQuery(event)` JSON 序列化作为缓存键,避免不同筛选条件互相污染。
### 后端响应包络
NestJS 全局 `TransformInterceptor` 把所有响应包成 `{ data: T, success: true }`。前端 `$fetch` 必须读取 `response.data`,类型定义也要带 `BackendEnvelope<T>` 包装层。
### `defineModel` 用于组件 v-model
Nuxt 4 内置 `defineModel` 支持双向绑定,比手写 `modelValue`/`update:modelValue` props+emit 更简洁:
```typescript
const keyword = defineModel<string>('keyword', { default: '' });
const emit = defineEmits<{ search: [] }>();
```
父组件用法:`<ProductFilterBar v-model:keyword="searchKeyword" @search="onSearch" />`
### SSR 期间 watch query 触发请求
在 `<script setup>` 中用 `await loadFilters()` 等顶层 await 时,Nuxt 会等待 Promise 解析才渲染首屏 HTML;之后用 `watch(() => [query.countryId, ...], fetchProducts)` 监听筛选条件变化,重新拉取数据。Top-level await 在 Nuxt 中是合法的(会变为异步 setup)。
### `npm install` 与 `node_modules`
首次 clone 项目后必须 `npm install` 安装依赖(项目使用 `package-lock.json`),否则 `node_modules` 为空。`npm install` 会自动触发 `postinstall: nuxt prepare` 生成 `.nuxt/` 类型与组件清单。
### 类型检查
项目使用 Nuxt 4 默认的 TS 配置(`.nuxt/tsconfig.app.json` 等)。运行类型检查:
```bash
npx vue-tsc --noEmit -p ./.nuxt/tsconfig.app.json
```
退出码 0 表示无类型错误,可作为合并前的本地验证步骤。