chore(qa): 验收台账与证据入库 + 构建/部署配置同步

- docs/acceptance/qa-tracker.md:跨周期缺陷单一真源台账(§7=第五轮)。
- 周期 1/2 + iPhone SE/axe 验收证据目录、ACCEPTANCE_REVIEW 快照入库。
- 同步 README/CONTEXT/CLAUDE/DESIGN/testing/deployment/lessons-learned 口径;
  next.config/Dockerfile/nginx/Jenkinsfile/docker-compose/sentry/prisma 对齐
  standalone 产物装配与部署形态。
This commit is contained in:
2026-09-28 10:48:09 +08:00
parent 6bb7c557ee
commit a0328a623f
128 changed files with 22455 additions and 504 deletions
+52 -6
View File
@@ -1,3 +1,23 @@
# 构建 + 运行一体镜像。
#
# 服务契约来源(交叉验证):
# - node_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/output.md:
# output: 'standalone' 产出可独立部署的目录 + 精简 server.js;该 server **默认不含** public
# 与 static,需手工拷到 <standalone>/public 与 <standalone>/.next/static(本项目 distDir=dist,
# 实测为 <standalone>/dist/static,见下);监听地址/端口由 HOSTNAME / PORT 环境变量决定。
# - 本仓库 dist/ 实测:dist/standalone/server.js、dist/standalone/dist/{BUILD_ID,server,...}、
# dist/static/{chunks,media,<buildId>}。
#
# 与 Dockerfile.prod 的分工(避免第三种变体):
# - Dockerfile.prod:直接复用**宿主机已构建**的 dist/standalone,宿主为 darwin,
# 因此需要 sharp-deps 阶段补 linux-musl 的 @img 二进制。
# - 本文件:镜像内完成 npm ci + next build(依赖原生装到 linux-musl),无需覆盖 @img。
#
# 历史缺陷(ACCEPTANCE_REVIEW_2026-09-21 §5):旧版把 /app/dist 当静态 HTML 根
# `COPY --from=builder /app/dist /usr/share/nginx/html` 交给 nginx,standalone 产物里没有
# 可直服的站点根目录(HTML 在 dist/standalone/dist/server/app/*.html,且需运行时渲染),
# 用本镜像部署即白屏/404。
FROM node:20-alpine AS builder
WORKDIR /app
@@ -9,13 +29,39 @@ COPY . .
ENV NEXT_TELEMETRY_DISABLED=1
RUN npm run build
# 先删除构建上下文里带进来的宿主产物:.dockerignore 为 Dockerfile.prod 放行了
# dist/standalone 与 dist/static,而 next build 不会清空目标目录,残留的
# dist/standalone/node_modules/@img/*-darwin-* 会被下面的 runner 原样拷进 linux 镜像。
RUN rm -rf "${NEXT_DIST_DIR:-dist}" && npm run build
FROM nginx:alpine
FROM node:20-alpine AS runner
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx-static.conf /etc/nginx/nginx.conf
WORKDIR /app
EXPOSE 80
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
ENV PORT=3000
# standalone server 只绑 HOSTNAME,默认 localhost 在容器外不可达
ENV HOSTNAME="0.0.0.0"
CMD ["nginx", "-g", "daemon off;"]
RUN addgroup --system --gid 1001 nodejs && \
adduser --system --uid 1001 nextjs
# Next.js 16 standalone 输出:server.js 位于 dist/standalone 根目录(与 Dockerfile.prod 一致)
# 注:以下三个路径按 next.config.mjs 的默认 distDir=dist 硬编码;若 CI 用 NEXT_DIST_DIR 改目录,
# 需同步这里的 --from 路径(当前 Jenkinsfile 未设置该变量)。
COPY --from=builder /app/dist/standalone ./
# 客户端静态资源,standalone 内的 distDir 影子目录为 dist/
COPY --from=builder /app/dist/static ./dist/static
# 公共静态资源(图片、字体、favicon、uploads)
COPY --from=builder /app/public ./public
RUN chown -R nextjs:nodejs /app
USER nextjs
EXPOSE 3000
# 应用层安全响应头由 next.config.mjs 的 headers() 发出,本镜像不再叠加 nginx 层,
# 因此容器直连(无 nginx)时头部依然完整。
CMD ["node", "server.js"]