Files
skelet/docs/04-architecture.md

10 KiB
Raw Permalink Blame History

架构设计

本文讲“怎么把技术栈搭起来”:系统结构、职责划分、数据模型、技术难点、开发顺序。

一、系统结构

游客 / 搜索引擎 / 后台编辑者
  |
  v
Nginx
  |
  v
Gunicorn
  |
  v
Django + Wagtail
  |
  +--> Wagtail Pages / Snippets / Admin
  +--> Templates / Static / Media
  |
  v
SQLite db.sqlite3

第一版没有独立前端应用,也没有公开业务 API。页面由 Wagtail/Django 渲染。

二、职责划分

Wagtail / Django

  • 管理页面、骨架项目、分类、标签、评分和文章。
  • 提供后台编辑、草稿、发布、slug、SEO 字段。
  • 渲染公开页面。
  • 提供基础搜索和筛选。

模板层

  • 首页、场景页、语言页、框架页、骨架详情页、文章页。
  • 展示筛选状态、空状态、评分、推荐理由、外部链接。
  • 不承载业务规则和数据修正逻辑。

数据层

  • SQLite 保存 Wagtail 内容、用户、权限、页面树、项目条目和评分。
  • media/ 保存上传图片。
  • 不在数据库保存真实密钥、token 或第三方平台凭证。

部署层

  • Nginx 处理 HTTPS、静态文件、媒体文件和反向代理。
  • Gunicorn 运行 Django。
  • SQLite 文件和 media 目录必须纳入备份。

三、数据模型

3.1 Wagtail Page 类型

模型 类型 说明
HomePage Page 首页,展示场景入口、推荐骨架、最新文章。
ScenarioIndexPage Page 场景总览页。
ScenarioPage Page 单个场景页,如 SaaS、管理后台、API 服务。
ProjectIndexPage Page 项目列表页(/projects/),承载筛选与分页。
SkeletonProjectPage Page 骨架项目详情页。
ArticleIndexPage Page 文章列表。
ArticlePage Page 评测、对比、避坑指南等内容文章。

模型归属:HomePage 在 home app(wagtail start 生成,沿用不改名);其余 Page、Snippet 和文章模型集中在 core app(见本文第六节)。

页面树结构(唯一权威):

HomePage (/)
├── ScenarioIndexPage (/scenarios/)
│   └── ScenarioPage (/scenarios/{slug}/)
├── ProjectIndexPage (/projects/)
│   └── SkeletonProjectPage (/projects/{slug}/)
└── ArticleIndexPage (/articles/)
    └── ArticlePage (/articles/{slug}/)
  • 项目详情页统一挂在 ProjectIndexPage 下,不挂在场景页下:一个项目属于多个场景(多对多),而页面树上只能有一个父节点。
  • ScenarioPage 没有子项目页;它通过查询 SkeletonProjectPage.objects.live().filter(scenarios=...) 渲染本场景的项目列表。
  • 列表筛选与分页在 ProjectIndexPage.get_context() 中做服务端查询实现(参数契约见 3.4),不另建独立 Django view。
  • /languages/{slug}/、/frameworks/{slug}/ MVP 由筛选参数替代,不建 Page(见 routes.md)。

Wagtail 实现注意:Page 模型上的多对多字段(scenarios、languages、frameworks、databases、features)必须用 modelcluster 的 ParentalManyToManyField,不能用 Django 普通 ManyToManyField,否则后台编辑、草稿和预览会出错。

3.2 Snippet / 辅助模型

模型 说明
Language Python、TypeScript、Go、Java、PHP 等。
Framework Wagtail、Django、FastAPI、Next.js、Laravel 等。
DatabaseOption SQLite、PostgreSQL、MySQL、MongoDB 等。
SkeletonFeature Auth、Admin、Payment、SEO、Docker、Tests 等功能标签。
AiCodingScore MVP 不建此模型:评分维度即 SkeletonProjectPage 的 6 个分数字段(见 3.3),避免两处维护同一套维度。
SponsorSlot 后续赞助展示位置,MVP 可先不启用。
AffiliateLink 后续返佣链接,MVP 可先不启用。

3.3 SkeletonProjectPage 核心字段

字段 类型 说明
title Wagtail Page title 项目名称。
summary Text 一句话简介。
github_url URL GitHub 地址。
official_url URL,可空 官网或文档。
license_name Char 开源协议。
scenarios 多对多 适合场景。一个骨架常同时适合多个场景(如 SaaS 和管理后台),必须按多对多实现,避免上线后再迁移。
languages 多选 使用语言。
frameworks 多选 使用框架。
databases 多选 支持数据库。
features 多选 功能标签。
maturity Choice experimental / stable / mature。
maintenance_status Choice active / slow / unknown / archived。
structure_score Integer 0-5 目录结构清晰度。
docs_score Integer 0-5 文档完整度。
tests_score Integer 0-5 测试可用性。
example_score Integer 0-5 示例模块完整度。
dependency_score Integer 0-5 依赖克制度。
incremental_score Integer 0-5 增量开发难度(agent 在既有模式中添加功能是否有清晰落点;含任务切片友好度)。
recommended_for RichText / StreamField 适合什么情况。
not_recommended_for RichText / StreamField 不适合什么情况。
review_notes RichText / StreamField 编辑评测。
is_featured Boolean 是否首页推荐。
is_sponsored Boolean 是否赞助展示,必须前台标识。

必填 / 可空 / 默认(后台校验以此为准,实现不得自行猜测):

  • 必填:title、summary、github_url、scenarios(至少 1 个)、languages(至少 1 个)、maturity、6 个评分字段、recommended_for。
  • 可空:official_url、license_name、frameworks、databases、features、not_recommended_for、review_notes。
  • 默认:maintenance_status='unknown'、is_featured=False、is_sponsored=False。
  • 6 个评分字段使用 MinValueValidator(0) / MaxValueValidator(5)。

评分模型纪律(唯一权威定义):

  • AI Coding 友好度评分维度以上表 6 个 0-5 分项为唯一权威:目录结构、文档完整度、测试可用性、示例模块、依赖克制度、增量开发难度。
  • 总分不单独录入,由 6 个分项计算得出(总和 0-30,前台可换算为百分制展示),用模型 property 或注解实现,避免人工维护时总分和分项对不上。
  • business/ 下的文档引用本节,不得自行维护另一份维度清单。
  • 每个项目除分数外必须有一句评语:为什么适合 / 不适合 AI coding。

3.4 URL 与筛选参数契约(唯一权威)

筛选条件必须可以通过 URL 表达,便于 SEO 和分享。列表页查询参数按下表实现,视图、模板和其他文档不得另造参数名或语义:

参数 取值 语义
language Language.slug,单值 项目 languages 包含该语言
framework Framework.slug,单值 项目 frameworks 包含该框架
database DatabaseOption.slug,单值 项目 databases 包含该数据库
min_score 0-30 整数 total_score(6 分项之和)≥ 该值
q 关键词字符串 title 或 summary 不区分大小写包含(ORM icontains,MVP 不接搜索后端)
page ≥1 整数 分页页码,每页 20 条

组合规则:

  • 参数均可选,多个参数同时出现时按 AND 组合。
  • MVP 每个参数只取单值;同名参数重复出现时取第一个。
  • min_score / page 无法解析为合法整数时忽略该参数,不报错。
  • 未知 slug 正常参与过滤,自然得到空列表并渲染空状态。

示例:

/scenarios/saas/
/scenarios/saas/?language=python
/projects/?framework=wagtail&database=sqlite&min_score=18
/projects/?q=admin&page=2

MVP 使用服务端查询和分页,不做前端复杂状态管理。

四、关键技术难点

难点 说明 应对
Wagtail 内容模型设计 Page 和 Snippet 边界如果设计错,后续迁移成本高。 先实现最小字段,避免过度抽象;模型变化同步文档。
SQLite 上线 读多写少可行,但并发写有限。 MVP 不做前台写入;启用 WAL;设置迁移 PostgreSQL 条件。
筛选与 SEO 筛选如果只靠前端状态,不利于搜索引擎和分享。 使用服务端查询和可分享 URL。
评分可信度 AI 友好度评分容易主观。 固定评分维度,详情页展示评分理由。
赞助与推荐冲突 商业化会损害信任。 Sponsored 必须显式标识,和编辑推荐分离。

五、推荐开发顺序

  1. 初始化 Wagtail 项目骨架,确认 Python 3.12 + SQLite 可运行。
  2. 建立基础 Page / Snippet 模型和迁移。
  3. 在后台录入首批示例数据。
  4. 实现首页、场景页、列表页、详情页。
  5. 实现筛选、基础搜索、空状态。
  6. 补 SEO、sitemap、robots、部署说明。
  7. 上线前配置 SQLite WAL、备份策略、Nginx/Gunicorn。

六、项目结构建议

T-001 初始化后目标结构(与 wagtail start skelet . 的实际输出对齐):

skelet/
├── docs/
├── manage.py
├── requirements.txt
├── skelet/            # wagtail start 生成的配置包
│   ├── settings/      # base.py / dev.py / production.py
│   ├── urls.py
│   └── wsgi.py
├── home/              # wagtail start 生成,保留,承载 HomePage
├── search/            # wagtail start 生成,保留
├── core/              # 新建业务 app:Snippet、场景页、项目页、文章模型
│   ├── models.py
│   ├── templates/
│   ├── static/
│   └── tests.py
├── media/
└── README.md

结构决策:保留 wagtail start 生成的 home 和 search app;业务模型全部放在新建的 core app;测试放各 app 的 tests.py,暂不建独立 tests/ 目录;Dockerfile 已删除。

已初始化:Wagtail 7.4.2 + Django 6.0.6,SQLite 可用,superuser admin 已创建。

七、架构纪律

  • 业务事实和 schema 变化必须同步更新本文。
  • 不在代码里发明文档没有的接口、字段和状态。
  • 不把静态内容、用户数据、缓存数据混在一个模型里。
  • 高风险模块先单独验证,再接入完整页面或流程。