Files
official-site-base/docs/plans/2026-07-23-phase0-tech-validation.md
T

26 KiB
Raw Blame History

Phase 0 技术验证 Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: 本地跑通「客户在 Sveltia CMS 改内容 → 提交到自建 Gitea → Gitea Action 自动构建 Astro → ossutil 同步到阿里云 OSS」的完整链路,验证设计文档(../specs/2026-07-23-official-site-cms-design.md)的技术可行性。

Architecture: Astro 5SSG)生成纯静态站;Sveltia CMS(CDN SPA)作为客户可视化后台,经 Gitea OAuth 提交 Markdown 到仓库;本地 Docker Gitea + act_runner 提供 Git 后端 + CI;构建产物由 ossutil 推到阿里云 OSS。内容用 Astro Content Collections + Zod schema 强类型校验。

Tech Stack: Astro 5 · Sveltia CMS · Gitea+Gitea Actions / act_runner)· ossutil · 阿里云 OSS · Vitest

前置条件: 本机已装 Node.js 20+、Docker;后续接真实 OSS 时需阿里云账号 + AK/SK + 已建 bucket。


Scope

本计划只覆盖 Phase 0 技术验证(设计文档 §十二 Phase 0)。Phase 1 基座化、Phase 2 首客户上线、Phase 3 Payload 适配器各自后续单独出计划。

验证成功标准(端到端):http://localhost:4321/admin/ 用 Sveltia 新增一条新闻 → 提交 → 本地 Gitea 收到 commit → Gitea Action 触发并构建成功 → dist/ 生成新页面 → ossutil 脚本可把 dist/ 同步到 OSS(凭据就绪时实推)。


File Structure

official-site-base/
├── package.json                      # 依赖:astro, vitest
├── astro.config.mjs                  # Astro 配置
├── tsconfig.json
├── vitest.config.ts
├── src/
│   ├── content.config.ts             # Content Collectionsnews+ schema 引用
│   ├── content/
│   │   ├── schemas.ts                # Zod schema(可单独单测)
│   │   └── news/
│   │       └── welcome.md            # 示例新闻
│   ├── layouts/BaseLayout.astro
│   ├── pages/
│   │   ├── index.astro               # 首页
│   │   └── news/
│   │       ├── index.astro           # 新闻列表
│   │       └── [slug].astro          # 新闻详情
│   └── styles/global.css             # 设计 token(白标入口)
├── public/
│   ├── admin/
│   │   ├── index.html                # Sveltia CMS 入口
│   │   └── config.yml                # Sveltia 配置(gitea backend
│   └── favicon.svg
├── tests/content-schema.test.ts      # Zod schema 单测
├── scripts/deploy-oss.sh             # ossutil 发布脚本
├── .gitea/workflows/deploy.yml       # Gitea Action
├── docker/gitea.docker-compose.yml   # 本地 Gitea + runner
├── .env.example                      # OSS 凭据模板
└── docs/{specs,plans}/...

职责边界:

  • src/content/schemas.ts —— 纯 Zod schema,与 Astro 解耦,可单测
  • src/content.config.ts —— 把 schema 绑到 collection,定义 loader
  • public/admin/config.yml —— Sveltia 字段配置,与 schema 字段保持一致(重复但必要:Sveltia 是 YAML、Astro 是 TS
  • scripts/deploy-oss.sh —— 独立发布脚本,本地和 CI 共用(DRY)

Task 1: 初始化 Astro 项目 + 工具链

Files:

  • Create: package.json, astro.config.mjs, tsconfig.json, vitest.config.ts

  • Create: src/styles/global.css, public/favicon.svg, .env.example

  • Step 1: 初始化 Astro 项目(在 official-site-base 目录内)

# 已在 official-site-base 目录,初始化最小 Astro(不加模板)
npm init -y
npm install astro@latest
npm install -D vitest@latest
  • Step 2: 写 package.json scripts

package.jsonscripts 改为:

{
  "name": "official-site-base",
  "type": "module",
  "version": "0.1.0",
  "scripts": {
    "dev": "astro dev",
    "build": "astro build",
    "preview": "astro preview",
    "test": "vitest run"
  }
}
  • Step 3: 写 astro.config.mjs
import { defineConfig } from 'astro/config';

export default defineConfig({
  site: 'https://example.com',
});
  • Step 4: 写 tsconfig.json
{
  "extends": "astro/tsconfigs/strict",
  "include": [".astro/types.d.ts", "**/*"],
  "exclude": ["dist"]
}
  • Step 5: 写 vitest.config.ts
import { defineConfig } from 'vitest/config';

export default defineConfig({
  test: {
    include: ['tests/**/*.test.ts'],
  },
});
  • Step 6: 写设计 token 入口 src/styles/global.css
:root {
  /* 白标入口:换客户时改这里 */
  --color-primary: #007aff;
  --color-text: #1a1a1a;
  --color-bg: #ffffff;
  --font-sans: system-ui, -apple-system, 'PingFang SC', 'Microsoft YaHei', sans-serif;
}

html { font-family: var(--font-sans); color: var(--color-text); background: var(--color-bg); }
body { margin: 0; max-width: 960px; margin-inline: auto; padding: 1.5rem; }
a { color: var(--color-primary); }
  • Step 7: 写 public/favicon.svg 与 .env.example

public/favicon.svg:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><rect width="32" height="32" rx="6" fill="#007aff"/><text x="16" y="22" font-size="18" text-anchor="middle" fill="#fff" font-family="sans-serif">O</text></svg>

.env.example:

# 阿里云 OSS 发布凭据(复制为 .env 后填真值,.env 已被 .gitignore 排除)
OSS_ACCESS_KEY_ID=
OSS_ACCESS_KEY_SECRET=
OSS_ENDPOINT=oss-cn-hangzhou.aliyuncs.com
OSS_BUCKET=official-site-base-demo
OSS_REGION=cn-hangzhou
# 本地 Gitea
GITEA_BASE_URL=http://localhost:3000
  • Step 8: 验证 Astro 能起

Run: npx astro --version && npm run dev,浏览器开 http://localhost:4321Ctrl+C 停止。 Expected: 版本号输出(5.x);dev server 起来无报错(此时还没有页面,404 正常)。

  • Step 9: Commit
git add -A
git commit -m "feat: 初始化 Astro 项目与工具链(vitest/设计token/env"

Task 2: news Content Collection + Zod schemaTDD

Files:

  • Create: src/content/schemas.ts, src/content.config.ts, src/content/news/welcome.md

  • Test: tests/content-schema.test.ts

  • Step 1: 写失败测试 tests/content-schema.test.ts

import { describe, it, expect } from 'vitest';
import { newsSchema } from '../src/content/schemas';

describe('newsSchema', () => {
  it('accepts valid frontmatter and coerces date', () => {
    const parsed = newsSchema.parse({
      title: '官网基座启动',
      date: '2026-07-23',
      category: '公告',
    });
    expect(parsed.title).toBe('官网基座启动');
    expect(parsed.date).toEqual(new Date('2026-07-23'));
    expect(parsed.category).toBe('公告');
  });

  it('defaults category to 未分类', () => {
    const parsed = newsSchema.parse({ title: '测试', date: '2026-07-23' });
    expect(parsed.category).toBe('未分类');
  });

  it('rejects missing title', () => {
    expect(() => newsSchema.parse({ date: '2026-07-23' })).toThrow();
  });

  it('rejects missing date', () => {
    expect(() => newsSchema.parse({ title: '测试' })).toThrow();
  });
});
  • Step 2: 运行测试,确认失败

Run: npm test Expected: FAIL —— Cannot find module '../src/content/schemas'(文件还没建)。

  • Step 3: 写 schema src/content/schemas.ts
import { z } from 'astro:content';

export const newsSchema = z.object({
  title: z.string(),
  date: z.coerce.date(),
  category: z.string().default('未分类'),
});

z 直接从 astro:content 导出(Astro 内置 zod,无需单独装)。

  • Step 4: 写 collection 配置 src/content.config.ts
import { defineCollection } from 'astro:content';
import { glob } from 'astro/loaders';
import { newsSchema } from './content/schemas';

const news = defineCollection({
  loader: glob({ pattern: '**/*.md', base: './src/content/news' }),
  schema: newsSchema,
});

export const collections = { news };
  • Step 5: 写示例内容 src/content/news/welcome.md
---
title: 官网基座启动
date: 2026-07-23
category: 公告
---

这是 Phase 0 技术验证的第一条新闻。内容编辑链路跑通后,客户可在 Sveltia CMS 自助新增。
  • Step 6: 运行测试,确认通过

Run: npm test Expected: PASS4 个测试全过)。

  • Step 7: Commit
git add -A
git commit -m "feat: 新增 news 内容集合与 Zod schema(含单测)"

Task 3: 首页 + 新闻列表/详情页面

Files:

  • Create: src/layouts/BaseLayout.astro, src/pages/index.astro, src/pages/news/index.astro, src/pages/news/[slug].astro

  • Step 1: 写 BaseLayout src/layouts/BaseLayout.astro

---
import '../styles/global.css';
interface Props { title: string; }
const { title } = Astro.props;
---
<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link rel="icon" href="/favicon.svg" />
    <title>{title}</title>
  </head>
  <body>
    <header><a href="/" style="font-weight:700;font-size:1.25rem;">官网基座</a></header>
    <main><slot /></main>
    <footer style="margin-top:3rem;font-size:.85rem;color:#888;">© 官网基座</footer>
  </body>
</html>
  • Step 2: 写首页 src/pages/index.astro
---
import BaseLayout from '../layouts/BaseLayout.astro';
import { getCollection } from 'astro:content';

const news = (await getCollection('news')).sort(
  (a, b) => b.data.date.getTime() - a.data.date.getTime()
);
---
<BaseLayout title="官网基座 · 首页">
  <h1>官网基座</h1>
  <p>Phase 0 技术验证站点。</p>
  <section>
    <h2>最新动态</h2>
    <ul>
      {news.map((post) => (
        <li><a href={`/news/${post.id}/`}>{post.data.title}</a> <small>{post.data.date.toLocaleDateString('zh-CN')}</small></li>
      ))}
    </ul>
    <p><a href="/news/">查看全部 →</a></p>
  </section>
</BaseLayout>
  • Step 3: 写新闻列表 src/pages/news/index.astro
---
import BaseLayout from '../../layouts/BaseLayout.astro';
import { getCollection } from 'astro:content';

const news = (await getCollection('news')).sort(
  (a, b) => b.data.date.getTime() - a.data.date.getTime()
);
---
<BaseLayout title="新闻动态">
  <h1>新闻动态</h1>
  <ul>
    {news.map((post) => (
      <li>
        <a href={`/news/${post.id}/`}>{post.data.title}</a>
        <small> · {post.data.category} · {post.data.date.toLocaleDateString('zh-CN')}</small>
      </li>
    ))}
  </ul>
</BaseLayout>
  • Step 4: 写新闻详情 src/pages/news/[slug].astro
---
import BaseLayout from '../../layouts/BaseLayout.astro';
import { getCollection, render } from 'astro:content';

export async function getStaticPaths() {
  const news = await getCollection('news');
  return news.map((post) => ({
    params: { slug: post.id },
    props: { post },
  }));
}

const { post } = Astro.props;
const { Content } = await render(post);
---
<BaseLayout title={post.data.title}>
  <article>
    <h1>{post.data.title}</h1>
    <p><small>{post.data.category} · {post.data.date.toLocaleDateString('zh-CN')}</small></p>
    <Content />
  </article>
  <p><a href="/news/">← 返回列表</a></p>
</BaseLayout>
  • Step 5: 构建并验证产物

Run: npm run build Expected: dist/index.htmldist/news/index.htmldist/news/welcome/index.html 生成,无报错。

Run: npm run preview,浏览器开 http://localhost:4321,点进新闻详情。 Expected: 首页列出到「官网基座启动」一条;详情页正文渲染。

  • Step 6: Commit
git add -A
git commit -m "feat: 首页与新闻列表/详情页面"

Task 4: Sveltia CMS 接入(/admin

Files:

  • Create: public/admin/index.html, public/admin/config.yml

  • Step 1: 写 CMS 入口 public/admin/index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="robots" content="noindex" />
    <title>Sveltia CMS</title>
  </head>
  <body>
    <!-- 注意:不要加 type="module",不要加 CSS linkSveltia 自带样式) -->
    <script src="https://unpkg.com/@sveltia/cms/dist/sveltia-cms.js"></script>
  </body>
</html>

国内生产环境可把 sveltia-cms.js 自托管到 OSS 或换国内 CDN(unpkg 国内可能慢),Phase 0 先用官方 CDN 验证。

  • Step 2: 写 Sveltia 配置 public/admin/config.yml
# yaml-language-server: $schema=https://unpkg.com/@sveltia/cms/schema/sveltia-cms.json

# 本地验证用本地 Gitea(Task 5 起的);生产换真实 Gitea 地址
backend:
  name: gitea
  repo: lzy/official-site-base
  base_url: http://localhost:3000
  api_root: http://localhost:3000/api/v1

media_folder: /public/media
public_folder: /media

collections:
  - name: news
    label: 新闻动态
    label_singular: 新闻
    folder: /src/content/news
    create: true
    slug: '{{slug}}'
    fields:
      - { label: 标题, name: title, widget: string }
      - { label: 日期, name: date, widget: datetime, type: date }
      - { label: 分类, name: category, widget: string, default: 未分类 }
      - { label: 正文, name: body, widget: richtext }

Sveltia 的 folder 路径要和 Astro content.config.tsbase./src/content/news)一致;字段要和 newsSchema 一一对应(title/date/category)。

  • Step 3: 验证 CMS 界面能加载

Run: npm run dev,浏览器开 http://localhost:4321/admin/。 Expected: 看到 Sveltia CMS 登录/界面(此时还没连 Gitea,点登录会报错或重定向失败——属正常,Task 6 接 Gitea 后通)。

  • Step 4: Commit
git add -A
git commit -m "feat: 接入 Sveltia CMS/admin + gitea backend 配置)"

Task 5: 本地 Gitea + act_runnerDocker

Files:

  • Create: docker/gitea.docker-compose.yml

  • Step 1: 写 docker-compose docker/gitea.docker-compose.yml

services:
  gitea:
    image: gitea/gitea:1
    environment:
      - USER_UID=1000
      - USER_GID=1000
    volumes:
      - ./gitea-data:/data
    ports:
      - "3000:3000"   # Web
      - "2222:22"     # SSH
    restart: unless-stopped

  runner:
    image: gitea/act_runner:latest
    environment:
      - GITEA_INSTANCE_URL=http://gitea:3000
      - GITEA_RUNNER_REGISTRATION_TOKEN=phase0-local-token
    volumes:
      - ./runner-data:/data
      - /var/run/docker.sock:/var/run/docker.sock
    depends_on:
      - gitea
    restart: unless-stopped
  • Step 2: 启动 Gitea + runner
cd docker
docker compose -f gitea.docker-compose.yml up -d
docker compose -f gitea.docker-compose.yml ps

Expected: 两个容器 Up

  • Step 3: 完成 Gitea 首次安装(Web 向导)

浏览器开 http://localhost:3000

  • 数据库选 SQLite(默认)
  • 站点 URLhttp://localhost:3000
  • 创建管理员账户:用户名 lzy,密码自设(记牢)
  • 点「立即安装」

Expected: 安装完成,跳转登录页,能登入。

  • Step 4: 注册 runner 到 Gitea

在 Gitea Webhttp://localhost:3000/admin/actions/runners,确认 runner 容器已注册并 idlecompose 里 token 写死为 phase0-local-token,runner 自动注册)。如未注册,到「Site Administration → Actions → Runners」用 phase0-local-token 手动添加。

Expected: runners 列表有一条 idle 的 runner。

  • Step 5: 把 official-site-base 推到本地 Gitea
# 在 official-site-base 目录
git remote add local http://localhost:3000/lzy/official-site-base.git
# 先在 Gitea Web 「新建仓库」official-site-base(空仓库,不要勾 README
git push -u local main

Expected: 推送成功,Gitea 上能看到代码。

  • Step 6: Commit docker 配置
# 回 official-site-base 目录
git add docker/gitea.docker-compose.yml
git commit -m "chore: 本地 Gitea + act_runner docker-compose"

注意:docker/gitea-data/docker/runner-data/ 不要提交(本地数据),后续加到 .gitignore。

  • Step 7: 补 .gitignore 排除本地数据

.gitignore 末尾追加:

# 本地 Gitea/runner 数据
docker/gitea-data/
docker/runner-data/
git add .gitignore
git commit -m "chore: 忽略本地 Gitea/runner 数据目录"

Task 6: Gitea OAuth App + Sveltia 提交链路验证

Files:

  • Modify: public/admin/config.yml(确认 base_url

  • Step 1: 在 Gitea 创建 OAuth2 应用

Gitea Web:头像 → Settings → Applications → OAuth2 Applications → 「Create Application」:

  • Name: Sveltia CMS
  • Redirect URI: http://localhost:4321/admin/
  • 创建后记录 Client IDClient Secret

Expected: 拿到一对 Client ID / Secret。

  • Step 2: 在 Sveltia config 补 auth 配置

修改 public/admin/config.yml 的 backend 段(追加 app_id / client_idSveltia gitea backend 用 OAuth):

backend:
  name: gitea
  repo: lzy/official-site-base
  base_url: http://localhost:3000
  api_root: http://localhost:3000/api/v1
  # Gitea OAuth2 AppStep 1 创建)
  app_id: <填 Client ID>

client_secret 不写进配置(Sveltia gitea backend 走 PKCE/标准 OAuth 流,仅用 client_id + redirect;如 Gitea 要求 secret,参考 Sveltia Backends 文档配 auth_type)。Phase 0 若 PKCE 流不通,降级用 git-gateway 或本地 token 方式,记录到 spec 风险项。

  • Step 3: 验证 Sveltia 登录 Gitea

Run: npm run dev,浏览器开 http://localhost:4321/admin/,点登录。 Expected: 跳转到 Gitea 授权页 → 授权 → 回到 Sveltia 看到「新闻动态」集合,能看到 Task 2 的 welcome.md。

  • Step 4: 新增一条新闻并提交

在 Sveltia:进入「新闻动态」→「新增新闻」→ 填标题/日期/分类/正文 → 保存 → 「Publish」。 Expected: 提交成功,本地 Gitea 仓库(http://localhost:3000/lzy/official-site-base)出现新 commitsrc/content/news/ 多一个 md 文件。

  • Step 5: 拉取并验证内容进入构建
git pull local main
ls src/content/news/
npm run build

Expected: 新文件出现;build 产物 dist/news/<新slug>/index.html 生成。

  • Step 6: Commit config 调整
git add public/admin/config.yml
git commit -m "feat: Sveltia 接 Gitea OAuth,跑通提交链路"

Task 7: Gitea Action 自动构建

Files:

  • Create: .gitea/workflows/deploy.yml

  • Step 1: 写工作流 .gitea/workflows/deploy.yml

name: build-and-deploy

on:
  push:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install deps
        run: npm ci

      - name: Build
        run: npm run build

      - name: Upload dist artifact
        uses: actions/upload-artifact@v4
        with:
          name: dist
          path: dist/

      - name: Sync to OSS
        env:
          OSS_ACCESS_KEY_ID: ${{ secrets.OSS_ACCESS_KEY_ID }}
          OSS_ACCESS_KEY_SECRET: ${{ secrets.OSS_ACCESS_KEY_SECRET }}
          OSS_ENDPOINT: ${{ secrets.OSS_ENDPOINT }}
          OSS_BUCKET: ${{ secrets.OSS_BUCKET }}
        run: bash scripts/deploy-oss.sh

Gitea Actions 兼容 GitHub Actions 语法;secrets 在 Gitea 仓库 Settings → Actions → Secrets 配。OSS 同步在 Task 8 写脚本;本地验证时若未配 OSS secrets,该 step 会跳过(脚本内判空)。

  • Step 2: 推送触发 Action
git add .gitea/workflows/deploy.yml
git commit -m "ci: Gitea Action 构建并发布到 OSS"
git push local main
  • Step 3: 验证 Action 执行

Gitea Webhttp://localhost:3000/lzy/official-site-base/actions。 Expected: 看到一次 push 触发的运行,build 作业绿色,artifact dist 上传成功;Sync to OSS 步骤因无凭据显示跳过/失败(Task 8 配齐后转绿)。


Task 8: ossutil 发布脚本

Files:

  • Create: scripts/deploy-oss.sh

  • Step 1: 安装 ossutil(如未装)

# 参考 https://help.aliyun.com/document_detail/120075.html
# macOS/Linux:
curl -o /usr/local/bin/ossutil https://gosspublic.alicdn.com/ossutil/install.sh && bash /usr/local/bin/ossutil
ossutil version

Windows 下载 ossutil64.exe 放进 PATH。Phase 0 本地不强求装;CI 环境在 workflow 里装。

  • Step 2: 写脚本 scripts/deploy-oss.sh
#!/usr/bin/env bash
set -euo pipefail

# 判空:没配凭据时跳过(Phase 0 本地/未配 OSS 时不阻塞)
if [ -z "${OSS_ACCESS_KEY_ID:-}" ] || [ -z "${OSS_BUCKET:-}" ]; then
  echo "[deploy-oss] 未配置 OSS 凭据,跳过同步。"
  exit 0
fi

: "${OSS_ACCESS_KEY_SECRET:?需 OSS_ACCESS_KEY_SECRET}"
: "${OSS_ENDPOINT:?需 OSS_ENDPOINT}"
: "${OSS_BUCKET:?需 OSS_BUCKET}"

DIST_DIR="${1:-dist}"
[ -d "$DIST_DIR" ] || { echo "[deploy-oss] $DIST_DIR 不存在,请先 build"; exit 1; }

echo "[deploy-oss] 同步 $DIST_DIR → oss://$OSS_BUCKET/"
ossutil sync "$DIST_DIR" "oss://$OSS_BUCKET/" \
  -i "$OSS_ACCESS_KEY_ID" \
  -k "$OSS_ACCESS_KEY_SECRET" \
  -e "$OSS_ENDPOINT" \
  --force --delete

echo "[deploy-oss] 刷新 CDN(如配了 CDN_DOMAIN"
if [ -n "${CDN_DOMAIN:-}" ]; then
  ossutil cdn refresh --dirs "https://${CDN_DOMAIN}/" \
    -i "$OSS_ACCESS_KEY_ID" -k "$OSS_ACCESS_KEY_SECRET" -e "$OSS_ENDPOINT" || true
fi

echo "[deploy-oss] 完成"
  • Step 3: 本地空跑验证(无凭据应跳过)
chmod +x scripts/deploy-oss.sh
./scripts/deploy-oss.sh

Expected: 输出 [deploy-oss] 未配置 OSS 凭据,跳过同步。,退出码 0。

  • Step 4: 本地真实推送验证(需 OSS 凭据)

在阿里云控制台建 bucket(如 official-site-base-demo,公共读),拿 AK/SK

cp .env.example .env
# 编辑 .env 填真值
set -a; source .env; set +a   # bash 加载环境变量
npm run build
./scripts/deploy-oss.sh

Expected: 输出同步文件列表;浏览器开 https://official-site-base-demo.oss-cn-hangzhou.aliyuncs.com/index.html 能看到首页。

  • Step 5: 配 Gitea Secrets 让 CI 同步

Gitea Web:仓库 Settings → Actions → Secrets,新增:

  • OSS_ACCESS_KEY_IDOSS_ACCESS_KEY_SECRETOSS_ENDPOINTOSS_BUCKET

再 push 一次:

git add scripts/deploy-oss.sh
git commit -m "feat: ossutil 发布脚本(本地与 CI 共用)"
git push local main

Expected: CI 的 Sync to OSS 步骤变绿,OSS 内容更新。


Task 9: 端到端验证 + README 更新

Files:

  • Modify: README.md

  • Step 1: 端到端验证清单

按下列顺序操作并逐条勾选:

  • npm run dev,开 http://localhost:4321/admin/,登录 Gitea

  • Sveltia 新增一条新闻 → Publish

  • 本地 Gitea 仓库出现新 commit

  • git pull local main,本地 src/content/news/ 出现新 md

  • push 后 Gitea Action 触发并构建成功

  • OSS 同步成功(如已配凭据)

  • npm run build + preview,首页与详情页展示新内容

  • Step 2: 更新 README.md 状态段

把 README 的「状态」段从:

📋 设计已确认,待出实施计划(Phase 0 技术验证)。

改为:

✅ Phase 0 技术验证已跑通:Sveltia CMS → Gitea → Action → OSS 全链路。

## 本地开发
npm install
npm run dev          # 站点 http://localhost:4321CMS http://localhost:4321/admin/
docker compose -f docker/gitea.docker-compose.yml up -d   # 起 Gitea

## 发布
npm run build
./scripts/deploy-oss.sh   # 需配 .env 的 OSS 凭据
  • Step 3: 最终提交
git add README.md
git commit -m "docs: Phase 0 验证完成,更新 README 与本地开发说明"
git push local main

Self-Review

1. Spec 覆盖检查(对照 spec §五 内容模型 / §四架构 / §九部署):

  • news 集合 + Zod schemaTask 2)—— 代表 Content Collections 机制,其余 7 个集合在 Phase 1 基座化时按同模式补
  • Sveltia CMS /admin 可视化编辑(Task 4
  • 自建 Gitea + ActionsTask 5/7
  • 阿里云 OSS 发布(Task 8
  • 端到端链路验证(Task 9
  • ⏭ 留待后续计划:jobs/downloads/messages 集合、表单微服务、白标换 token 脚本、CMS 适配器接口(Phase 1-3

2. 占位符扫描: Task 6 Step 2 的 <填 Client ID> 是执行时填入的真实值(来自 Step 1 创建的 App),非 TODO 占位符;其余步骤代码完整。

3. 类型/命名一致性:

  • newsSchema 字段(title/date/category)在 Task 2 schema、Task 4 config.yml、Task 3 页面三处一致
  • collection 名 news 在 content.config.ts、config.yml、页面 getCollection('news') 一致
  • OSS 环境变量名(OSS_ACCESS_KEY_ID 等)在 .env.example、deploy-oss.sh、deploy.yml secrets 三处一致
  • Gitea 仓库路径 lzy/official-site-base 在 config.yml、push 命令一致

已知风险(执行时留意,已写入 spec §十一):

  • Gitea OAuth PKCE 流是否开箱通(Task 6 Step 2 注明了降级方案)
  • act_runner 注册 tokencompose 写死 phase0-local-token,仅本地)
  • unpkg CDN 国内访问速度(生产换自托管)

执行记录(2026-07-23 实施偏差与现状)

代码侧 Task 1-4、7、8 + Task 5 文件部分已完成(feat/phase0-tech-validation 分支,7 commit)。

实际依赖版本(偏离计划 @latest):

计划 实际 原因
astro latest(7.1) 5.18.2 latest 要 node≥22.12,本机 node 22.11 被拒启动
vitest latest(4) 3.2.7 latest(4) 依赖 rolldownWindows native binding 装不上
zod latest(4) 3.25.76 astro 5 内置 zod 3zod 4 与 astro:content 不兼容

其他调整:

  • Task 2 schema 改用独立 zod 包(import { z } from 'zod')而非 astro:content,让 vitest 能直接测(astro:content 是虚拟模块);版本与 astro 内置 dedupe 为同一份 3.25.76。
  • Sveltia CMS backends 已查实:原生支持 GitHub / GitLab / Gitea不支持 Gitee / Bitbucket(故选自建 Gitea,见 spec §三)。

验证已过: schema 单测 4 个全过;astro build 出 3 页;deploy-oss.sh 空跑跳过退出 0。

阻塞(待用户决策): 本机无 DockerTask 5(起 Gitea/ 6OAuth/ 9(端到端)无法本地跑通。Gitea 部署方式三选一:① 本地装 Docker Desktop ② 本地 Gitea 二进制 ③ 上服务器(ops 机或新轻量云)。