Files
inkreach-official-website/docs/references/structs.md
T
yeuimu c3472a449b feat(product-center): implement full product center with NestJS backend, Vue3 admin, and Nuxt4 website page
- NestJS backend: Prisma + PostgreSQL, JWT auth, CRUD for goods/categories/countries/tags/positions, SDS sync with cron, public API, Swagger docs
- Vue3 Admin: Element Plus, goods/categories/countries/tags/positions/sync management pages, batch operations, login with JWT
- Nuxt4 Website: product-center page with sidebar navigation, country filter, search, product grid, pagination, skeleton loading
- Nitro proxy routes for backend API
- 54 backend tests passing
- Updated docs and README
2026-06-15 10:09:42 +08:00

13 KiB
Raw Blame History

InkReach Product Center — Monorepo Structure

全局根目录结构说明。三个子项目独立维护各自 package.json 与技术栈,通过约定的端口协同工作。

根目录

inkreach-official/
├── .agents/                       # AI Agent 共享技能(brainstorming / TDD / git-spec / ...
├── docs/                          # 跨子项目文档
│   ├── dev/                       # 设计文档(数据库表设计、PRD、原型图)
│   │   ├── database-table-design.md
│   │   ├── product-center-prd.md
│   │   └── product-center-{1,2,3}.png
│   ├── references/
│   │   └── structs.md             # 本文件
│   └── superpowers/specs/         # superpowers 规格说明
├── plans/                         # 跨子项目计划
│   └── feature/
├── AGENTS.md                      # 根级 AI Agent 开发规范
├── skills-lock.json               # 技能版本锁定
├── .env                           # 根级环境变量(DATABASE_URL 等)
├── .git/                          # 单一 Git 仓库,trunk-based
├── inkreach-official-nestjs/      # 子项目 1NestJS 后端
├── inkreach-official-admin/       # 子项目 2Vue 3 后台
└── inkreach-official-website/     # 子项目 3Nuxt 4 官网

端口与子项目

子项目 端口 启动命令 说明
inkreach-official-nestjs 3001 npm run start:dev NestJS + Prisma + PostgreSQL 后端 APISwagger 文档 /api/docs
inkreach-official-admin 5173 npm run dev Vue 3 + Element Plus 后台管理;通过 Vite proxy /api → :3001
inkreach-official-website 3000 npm run dev Nuxt 4 官网;通过 Nitro server/api/backend/* 代理 :3001

启动顺序:先启动 inkreach-official-nestjs,再启动另两个。

子项目 1inkreach-official-nestjs(后端)

inkreach-official-nestjs/
├── prisma/
│   ├── schema.prisma              # 数据模型(OriginGood/Country/Category/Tag/Position/Good/User/SyncLog
│   └── migrations/                # Prisma migrate 历史
├── src/
│   ├── main.ts                    # 入口:CORS、ValidationPipe、Swagger、BigInt JSON 序列化
│   ├── app.module.ts              # 根模块,聚合所有业务模块
│   ├── prisma/                    # PrismaService 封装
│   ├── auth/                      # JWT 认证:register / login / JwtStrategy / JwtAuthGuard
│   ├── countries/                 # 国家 CRUD(受 JWT 保护)
│   ├── categories/                # 品类 CRUD(受 JWT 保护,自引用树)
│   ├── tags/                      # 标签 CRUD(受 JWT 保护)
│   ├── positions/                 # 坑位 CRUD(受 JWT 保护)
│   ├── origin-goods/              # SDS 原始商品快照(只读分页)
│   ├── goods/                     # 商品 CRUD + 批量优先级 + 批量创建
│   ├── sync/                      # SDS 同步:分类 / 商品 / 同步日志
│   ├── public/                    # 公开 API:分类树 / 国家 / 商品分页 / 商品详情
│   └── common/                    # 全局装饰器 / 过滤器 / 拦截器
│       ├── decorators/current-user.decorator.ts
│       ├── filters/http-exception.filter.ts
│       └── interceptors/transform.interceptor.ts
├── test/                          # e2e 测试
├── dist/                          # 构建产物
├── nest-cli.json
├── tsconfig.json / tsconfig.build.json
├── jest.config.js
└── package.json

数据模型(Prisma

模型 说明
OriginGood SDS 原始商品缓存,关联 sds_good_id(唯一)
Country 国家,关联 goods / positions
Category 自引用树形品类,可选 sds_category_id
Tag 标签,含 tagColortiming
Position 坑位:(country, category) 维度,关联多个 goods
Good 商品:originGood × country × category × tag? × position?,含 goodPriority
User 后台用户(bcrypt 哈希)
SyncLog 同步任务日志,含 SyncTypeCATEGORIES / PRODUCTS)和 SyncStatus

关键设计

  • 所有主键为 BigInt,路由解析后 BigInt(id) 处理,序列化时通过 BigInt.prototype.toJSON 转为字符串。
  • 全局 TransformInterceptor:把响应包装为 { data: T, success: true },前端读取 response.data
  • 全局 ValidationPipewhitelist + transform + forbidNonWhitelisted
  • 全局 HttpExceptionFilter:统一错误响应形态。
  • CORS 白名单http://localhost:5173admin)和 http://localhost:3000website)。
  • JWT:所有 /goods /categories /countries /tags /positions /origin-goods /sync/* 路由受 JwtAuthGuard 保护;/public/*/auth/* 公开。

API 路由

前缀 说明 鉴权
/auth/register POST 注册后台用户 公开
/auth/login POST 登录获取 JWT 公开
/public/categories GET 公开品类树(仅含已挂商品的品类) 公开
/public/countries GET 公开国家列表(仅含已挂商品的国家) 公开
/public/goods GET 分页商品(支持 countryId/categoryId/tagId/keyword/page/pageSize 公开
/public/goods/:id GET 商品详情 公开
/categories /tags /countries /positions 后台 CRUD JWT
/origin-goods GET SDS 原始商品快照分页 JWT
/goods 后台商品 CRUD + POST /goods/batch + PATCH /goods/batch-priority JWT
/sync/categories POST 手动触发分类同步 JWT
/sync/products POST 手动触发商品同步 JWT
/sync/status GET 最近同步日志(?limit=20 JWT
/api/docs Swagger UI 公开

子项目 2inkreach-official-admin(后台)

inkreach-official-admin/
├── public/                        # 静态资源
├── src/
│   ├── main.ts                    # 入口:Pinia + Vue Router + ElementPlus
│   ├── App.vue
│   ├── style.css                  # 全局样式(含品牌色变量)
│   ├── api/                       # 按业务模块拆分的 API 客户端
│   │   ├── request.ts             # axios 实例 + JWT 拦截 + 全局错误处理
│   │   ├── auth.ts                # /auth/login, /auth/me, /auth/logout
│   │   ├── goods.ts               # 商品 CRUD + 批量
│   │   ├── categories.ts          # 品类 CRUD
│   │   ├── countries.ts           # 国家 CRUD
│   │   ├── tags.ts                # 标签 CRUD
│   │   ├── positions.ts           # 坑位 CRUD
│   │   ├── origin-goods.ts        # 原始商品快照
│   │   └── sync.ts                # 同步触发 + 日志
│   ├── layouts/DefaultLayout.vue  # 侧边栏 + 顶部条 + 用户菜单
│   ├── router/index.ts            # 路由 + 登录守卫
│   ├── stores/
│   │   ├── auth.ts                # 登录态 + token + user(持久化到 localStorage
│   │   └── app.ts                 # 侧边栏折叠
│   ├── types/index.ts             # 共享类型
│   ├── views/
│   │   ├── login/LoginView.vue    # 登录
│   │   ├── goods/GoodsView.vue
│   │   ├── categories/CategoriesView.vue
│   │   ├── countries/CountriesView.vue
│   │   ├── tags/TagsView.vue
│   │   ├── positions/PositionsView.vue
│   │   └── sync/SyncView.vue
│   ├── auto-imports.d.ts          # 自动生成的自动导入类型
│   └── components.d.ts            # 自动生成的组件类型
├── index.html
├── vite.config.ts                 # Vite + ElementPlus 自动导入 + /api → :3001 代理
├── tsconfig.json / tsconfig.app.json / tsconfig.node.json
└── package.json

路由

路径 视图 鉴权
/login LoginView 公开
/goods GoodsView(默认页) JWT
/categories CategoriesView JWT
/countries CountriesView JWT
/tags TagsView JWT
/positions PositionsView JWT
/sync SyncView JWT
/:pathMatch(.*)* 重定向到 /goods

关键设计

  • Vite 代理/api/* 代理到 http://localhost:3001rewrite 去掉 /api 前缀。
  • axios 拦截器:请求注入 Authorization: Bearer <token>;响应直接返回 response.data401 自动登出跳转。
  • ElementPlus 自动导入:通过 unplugin-auto-import + unplugin-vue-components + ElementPlusResolver
  • 路由守卫:未登录访问受保护路由跳 /login;已登录访问 /login/
  • Pinia 持久化auth store 主动读写 localStoragetoken + user)。

子项目 3inkreach-official-website(官网)

inkreach-official-website/
├── app/
│   ├── app.vue                    # 根容器:<NuxtPage />
│   ├── pages/
│   │   ├── index.vue              # 首页
│   │   └── product-center.vue     # 产品中心(侧边栏 + 国家/筛选 + 网格 + 分页)
│   ├── assets/css/tailwind.css    # Tailwind v4 主题(@theme 定义颜色与动画)
│   ├── composables/
│   │   ├── useNavData.ts          # 导航数据(选品推荐/解决方案)
│   │   ├── usePodProducts.ts      # 首页 POD 产品(SDS
│   │   └── useProductCenter.ts    # 产品中心数据(调用 /api/backend/*
│   └── components/
│       ├── AppHeader.vue / AppFooter.vue
│       ├── nav/                   # 导航下拉面板
│       │   ├── NavMegaMenu.vue
│       │   └── NavColumnMenu.vue
│       ├── product/               # 产品中心专用组件
│       │   ├── ProductSidebar.vue        # 树形品类侧边栏
│       │   ├── ProductCountryFilter.vue  # 国家 pill 筛选
│       │   ├── ProductFilterBar.vue      # 搜索输入 + 按钮
│       │   ├── ProductCard.vue           # 商品卡片
│       │   ├── ProductCardSkeleton.vue   # 骨架占位
│       │   ├── ProductGrid.vue           # 网格容器
│       │   └── ProductPagination.vue     # 分页器
│       ├── HeroBanner.vue
│       ├── TrustSection.vue
│       ├── StepProcess.vue
│       ├── PodProducts.vue
│       ├── FeatureCards.vue
│       ├── WhyInkReach.vue
│       ├── CompanyProfile.vue
│       ├── CustomerCases.vue
│       └── CtaBanner.vue
├── server/                        # Nitro 后端
│   ├── api/
│   │   ├── pod/                   # 原有 SDS POD API 代理
│   │   └── backend/               # NestJS 后端代理(同源 + Nitro 缓存 60s)
│   │       ├── categories.get.ts        # → GET :3001/public/categories
│   │       ├── countries.get.ts         # → GET :3001/public/countries
│   │       ├── goods.get.ts             # → GET :3001/public/goods
│   │       └── goods/[id].get.ts        # → GET :3001/public/goods/:id
│   └── utils/pod-api.ts
├── public/                        # 静态资源
├── plans/feature/                 # 历史功能计划
├── docs/
│   ├── references/structs.md      # 子项目级结构文档
│   └── superpowers/specs/
├── nuxt.config.ts                 # runtimeConfig.public.backendUrl
├── .env                           # NUXT_PUBLIC_BACKEND_URL=http://localhost:3001
├── AGENTS.md                      # 子项目 AI Agent 规范
├── README.md
└── package.json

子项目内部的页面、组件、composable、代理路由、组件响应式断点等详细信息见 inkreach-official-website/docs/references/structs.md

数据库

  • PostgreSQL 14+Prisma 5.x
  • 连接配置在根 .envDATABASE_URL
  • 所有 TIMESTAMPTZ 列:@db.Timestamptz(6)
  • 所有主键:BigInt @default(autoincrement())
  • 表名与列名通过 @map / @@map 映射为 snake_case
  • 迁移位于 inkreach-official-nestjs/prisma/migrations/

环境变量总览

变量 位置 用途 默认
DATABASE_URL .env PostgreSQL 连接串
JWT_SECRET inkreach-official-nestjs JWT 签名密钥
PORT inkreach-official-nestjs 后端端口 3001
SDS_API_* inkreach-official-nestjs 同步上游 SDS 接口凭据
VITE_API_BASE inkreach-official-admin axios baseURL /api
NUXT_PUBLIC_BACKEND_URL inkreach-official-website NestJS 后端地址 http://localhost:3001