feat: publish Dever core with project scaffolding and versioned AI skills

This commit is contained in:
Antigravity committed 2026-10-04 13:37:30 +00:00
1 parent 70fa73cdc2
commit ac458ffa7f
960 files changed
+221319 -1163

No files matched your search

@@ -0,0 +1,58 @@
# 后台文章接口
普通管理使用 Model REST,发布保留为业务动作。
- 包:`news.article.api.admin.manage`
- 公开类型:无
- 公开方法:无
- 使用:无
## get list
普通管理使用 Model REST,发布保留为业务动作。
- 声明:`get list`
```dever
get list = app.list
```
## get detail
普通管理使用 Model REST,发布保留为业务动作。
- 声明:`get detail`
```dever
get detail = app.detail
```
## post create
普通管理使用 Model REST,发布保留为业务动作。
- 声明:`post create`
```dever
post create = app.create
```
## delete remove
普通管理使用 Model REST,发布保留为业务动作。
- 声明:`delete remove`
```dever
delete remove = app.remove
```
## 发布文章
本节定义对应的源码合同。
- 声明:`post publish`
```dever
post publish = app.publish
```
@@ -0,0 +1,28 @@
# 前台文章接口
前台只查询已发布内容,不开放自动 REST 写路由。
- 包:`news.article.api.front.browse`
- 公开类型:无
- 公开方法:无
- 使用:无
## 文章列表
本节定义对应的源码合同。
- 声明:`get list`
```dever
get list = app.published
```
## 文章详情
本节定义对应的源码合同。
- 声明:`get detail`
```dever
get detail = app.published_detail
```
@@ -0,0 +1,244 @@
# news.article.app.editing
文章创建、所有权查询与带版本的编辑;所有写入校验分类和媒体引用。
- 包:`news.article.app.editing`
- 公开类型:
- `ArticleView`
- `ArticlePage`
- 公开方法:
- `create`
- `list`
- `detail`
- `remove`
- `edit`
- `require_schedulable`
- 使用:
- `news.article.create(slug, title, body, category_id, asset_id)`
- `news.article.list(size)`
- `news.article.detail(id)`
- `news.article.remove(id)`
- `news.article.edit(id, expected_version, title, body, category_id, asset_id)`
- `news.article.require_schedulable(article_id)`
## ArticleView
文章创建、所有权查询与带版本的编辑;所有写入校验分类和媒体引用。
- 类型:`ArticleView`
- 字段:
- `id: model.id`:记录标识
- `slug: Text`:规范化标识
- `title: Text`:文章标题
- `body: Text`:正文
- `version: Int`:当前编辑版本
- `category_id: content.category.model.id?`:可选分类引用
- `asset_id: media.asset.model.id?`:可选媒体引用
```dever
type ArticleView {
id: model.id
slug: Text
title: Text
body: Text
version: Int
category_id: content.category.model.id?
asset_id: media.asset.model.id?
}
```
## ArticlePage
文章创建、所有权查询与带版本的编辑;所有写入校验分类和媒体引用。
- 类型:`ArticlePage`
- 字段:
- `rows: List<ArticleView>`:页面记录
- `total: Int`:所有权范围内总数
```dever
type ArticlePage {
rows: List<ArticleView>
total: Int
}
```
## create
文章创建、所有权查询与带版本的编辑;所有写入校验分类和媒体引用。
- 函数:`create`
- 输入:
- `slug: Text`:规范化标识
- `title: Text`:文章标题
- `body: Text`:正文
- `category_id: content.category.model.id?`:可选分类引用
- `asset_id: media.asset.model.id?`:可选媒体引用
- 输出:
- `article: ArticleView`:该声明的业务值
```dever
create(
slug: Text,
title: Text,
body: Text,
category_id: content.category.model.id?,
asset_id: media.asset.model.id?
) (article: ArticleView) {
normalized_slug = domain.normalize_slug(slug)
normalized_title = domain.normalize_title(title)
domain.require_content(normalized_slug, normalized_title, body)
content.category.require_active(category_id)
media.asset.require_ready(asset_id)
stored = model.create(
{
author_id = user.account.current_user()
slug = normalized_slug
title = normalized_title
body = body
category_id = category_id
asset_id = asset_id
}
)
article = detail(stored.id)
}
```
## list
文章创建、所有权查询与带版本的编辑;所有写入校验分类和媒体引用。
- 函数:`list`
- 输入:
- `size: Int`:受限页大小
- 输出:
- `articles: ArticlePage`:该声明的业务值
```dever
list(size: Int) (articles: ArticlePage) {
author = user.account.current_user()
articles = ArticlePage {
rows = model.owned_articles(author, domain.page_size(size))
total = model.count(
{
where = author_id == author
}
)
}
}
```
## detail
文章创建、所有权查询与带版本的编辑;所有写入校验分类和媒体引用。
- 函数:`detail`
- 输入:
- `id: news.article.model.id`:记录标识
- 输出:
- `article: ArticleView`:该声明的业务值
```dever
detail(id: model.id) (article: ArticleView) {
stored = model.get(id)
domain.require_owner(dever.auth.owns_user(stored.author_id))
article = ArticleView {
id = stored.id
slug = stored.slug
title = stored.title
body = stored.body
version = stored.version
category_id = stored.category_id
asset_id = stored.asset_id
}
}
```
## remove
文章创建、所有权查询与带版本的编辑;所有写入校验分类和媒体引用。
- 函数:`remove`
- 输入:
- `id: news.article.model.id`:记录标识
- 输出:
- `removed: Int`:该声明的业务值
```dever
remove(id: model.id) (removed: Int) {
stored = model.get(id)
domain.require_owner(dever.auth.owns_user(stored.author_id))
domain.require_draft(stored.status == model.ArticleStatus.Draft)
removed = model.delete(
{
where = id == stored.id and version == stored.version
}
)
domain.require_updated(removed)
}
```
## edit
文章创建、所有权查询与带版本的编辑;所有写入校验分类和媒体引用。
- 函数:`edit`
- 输入:
- `id: news.article.model.id`:记录标识
- `expected_version: Int`:调用者读取的编辑版本
- `title: Text`:文章标题
- `body: Text`:正文
- `category_id: content.category.model.id?`:可选分类引用
- `asset_id: media.asset.model.id?`:可选媒体引用
- 输出:
- `article: ArticleView`:该声明的业务值
```dever
edit(
id: model.id,
expected_version: Int,
title: Text,
body: Text,
category_id: content.category.model.id?,
asset_id: media.asset.model.id?
) (article: ArticleView) {
stored = model.get(id)
domain.require_owner(dever.auth.owns_user(stored.author_id))
domain.require_draft(stored.status == model.ArticleStatus.Draft)
normalized_title = domain.normalize_title(title)
domain.require_content(stored.slug, normalized_title, body)
content.category.require_active(category_id)
media.asset.require_ready(asset_id)
changed = model.update(
{
where = id == stored.id and version == expected_version and status == model.ArticleStatus.Draft
},
{
title = normalized_title
body = body
category_id = category_id
asset_id = asset_id
version = expected_version + 1
}
)
domain.require_updated(changed)
article = detail(stored.id)
}
```
## require_schedulable
文章创建、所有权查询与带版本的编辑;所有写入校验分类和媒体引用。
- 函数:`require_schedulable`
- 输入:
- `article_id: news.article.model.id`:文章标识
- 输出:无
```dever
require_schedulable(article_id: model.id) () {
stored = model.get(article_id)
domain.require_owner(dever.auth.owns_user(stored.author_id))
domain.require_draft(stored.status == model.ArticleStatus.Draft)
}
```
@@ -0,0 +1,203 @@
# news.article.app.publication
手动发布和定时任务共用原子发布流程,发布快照与审计同步提交。
- 包:`news.article.app.publication`
- 公开类型:无
- 公开方法:
- `publish`
- `published`
- `published_detail`
- `publish_scheduled`
- `scheduled_publication`
- `publish_draft`
- `existing_publication`
- 使用:
- `news.article.publish(article_id)`
- `news.article.published(size)`
- `news.article.published_detail(id)`
- `news.article.publish_scheduled(article_id)`
- `news.article.scheduled_publication(status, article_id)`
- `news.article.publish_draft(article_id)`
- `news.article.existing_publication(stored)`
## publish
手动发布和定时任务共用原子发布流程,发布快照与审计同步提交。
- 函数:`publish`
- 输入:
- `article_id: news.article.model.id`:文章标识
- 输出:
- `publication: news.article.model.publication.Publication`:该声明的业务值
```dever
transaction publish(article_id: model.id) (publication: model.publication.Publication) {
stored = model.get(article_id)
domain.require_owner(dever.auth.owns_user(stored.author_id))
domain.require_draft(stored.status == model.ArticleStatus.Draft)
publication = publish_draft(article_id)
}
```
## published
手动发布和定时任务共用原子发布流程,发布快照与审计同步提交。
- 函数:`published`
- 输入:
- `size: Int`:受限页大小
- 输出:
- `articles: news.article.model.publication.Page`:该声明的业务值
```dever
published(size: Int) (articles: model.publication.Page) {
articles = model.publication.list(
{
order = [published_at.desc, id.desc]
size = domain.page_size(size)
}
)
}
```
## published_detail
手动发布和定时任务共用原子发布流程,发布快照与审计同步提交。
- 函数:`published_detail`
- 输入:
- `id: news.article.model.publication.id`:记录标识
- 输出:
- `article: news.article.model.publication.Publication`:该声明的业务值
```dever
published_detail(id: model.publication.id) (article: model.publication.Publication) {
article = model.publication.get(id)
domain.require_published(text.trim(article.body) != "")
}
```
## publish_scheduled
手动发布和定时任务共用原子发布流程,发布快照与审计同步提交。
- 函数:`publish_scheduled`
- 输入:
- `article_id: news.article.model.id`:文章标识
- 输出:
- `publication: news.article.model.publication.Publication`:该声明的业务值
```dever
transaction publish_scheduled(article_id: model.id) (
publication: model.publication.Publication
) {
stored = model.get(article_id)
publication = scheduled_publication(stored.status, article_id)
}
```
## scheduled_publication
手动发布和定时任务共用原子发布流程,发布快照与审计同步提交。
- 函数:`scheduled_publication`
- 输入:
- `status: news.article.model.ArticleStatus`:业务状态
- `article_id: news.article.model.id`:文章标识
- 输出:
- `publication: news.article.model.publication.Publication`:该声明的业务值
```dever
scheduled_publication(status: model.ArticleStatus.Published, article_id: model.id) (
publication: model.publication.Publication
) {
stored = model.get(article_id)
publication = existing_publication(
model.publication.first(
{
where = slug == stored.slug
}
)
)
}
scheduled_publication(status: model.ArticleStatus.Draft, article_id: model.id) (
publication: model.publication.Publication
) {
publication = publish_draft(article_id)
}
```
## publish_draft
手动发布和定时任务共用原子发布流程,发布快照与审计同步提交。
- 函数:`publish_draft`
- 输入:
- `article_id: news.article.model.id`:文章标识
- 输出:
- `publication: news.article.model.publication.Publication`:该声明的业务值
```dever
publish_draft(article_id: model.id) (publication: model.publication.Publication) {
stored = model.get(article_id)
domain.require_draft(stored.status == model.ArticleStatus.Draft)
content.category.require_active(stored.category_id)
media.asset.require_ready(stored.asset_id)
published_at = dever.time.now()
changed = model.update(
{
where = id == stored.id and version == stored.version and status == model.ArticleStatus.Draft
},
{
status = model.ArticleStatus.Published
published_at = published_at
version = stored.version + 1
}
)
domain.require_updated(changed)
audit.operation.record(
audit.operation.model.OperationKind.Publish,
"article",
stored.slug
)
publication = model.publication.upsert(
{
slug = stored.slug
},
{
title = stored.title
body = stored.body
published_at = published_at
},
{
title = stored.title
body = stored.body
published_at = published_at
}
)
}
```
## existing_publication
手动发布和定时任务共用原子发布流程,发布快照与审计同步提交。
- 函数:`existing_publication`
- 输入:
- `stored: news.article.model.publication.Publication?`:该声明的业务值
- 输出:
- `publication: news.article.model.publication.Publication`:该声明的业务值
```dever
existing_publication(stored: model.publication.Publication) (
publication: model.publication.Publication
) {
publication = stored
}
existing_publication(stored: null) (publication: model.publication.Publication) {
fail(dever.api.Error.NotFound)
}
```
@@ -0,0 +1,162 @@
# 文章规则
文章字段规范化、分页边界和发布状态规则集中在纯 Domain。
- 包:`news.article.domain`
- 公开类型:无
- 公开方法:无
- 使用:无
## 规范文章标识
本节定义对应的源码合同。
- 函数:`normalize_slug`
- 输入:
- `value: Text`:该声明的业务值
- 输出:
- `slug: Text`:规范化标识
```dever
normalize_slug(value: Text) (slug: Text) pure {
slug = text.lower(text.trim(value))
}
```
## 规范标题
本节定义对应的源码合同。
- 函数:`normalize_title`
- 输入:
- `value: Text`:该声明的业务值
- 输出:
- `title: Text`:文章标题
```dever
normalize_title(value: Text) (title: Text) pure {
title = text.trim(value)
}
```
## 限制分页大小
本节定义对应的源码合同。
- 函数:`page_size`
- 输入:
- `value: Int`:该声明的业务值
- 输出:
- `size: Int`:受限页大小
```dever
page_size(value: Int >= 1 and <= 100) (size: Int) pure {
size = value
}
page_size(value: other) (size: Int) pure {
fail(dever.api.Error.Invalid)
}
```
## 检查草稿状态
本节定义对应的源码合同。
- 函数:`require_draft`
- 输入:
- `draft: Bool`:该声明的业务值
- 输出:无
```dever
require_draft(draft: true) () pure {}
require_draft(draft: false) () pure {
fail(dever.api.Error.Conflict)
}
```
## 检查文章所有权
发布操作只允许文章作者执行。
- 函数:`require_owner`
- 输入:
- `owned: Bool`:该声明的业务值
- 输出:无
```dever
require_owner(owned: true) () pure {}
require_owner(owned: false) () pure {
fail(dever.api.Error.Forbidden)
}
```
## require_published
文章字段规范化、分页边界和发布状态规则集中在纯 Domain。
- 函数:`require_published`
- 输入:
- `published: Bool`:该声明的业务值
- 输出:无
```dever
require_published(published: true) () pure {}
require_published(published: false) () pure {
fail(dever.api.Error.NotFound)
}
```
## require_updated
文章字段规范化、分页边界和发布状态规则集中在纯 Domain。
- 函数:`require_updated`
- 输入:
- `changed: Int`:条件更新影响行数
- 输出:无
```dever
require_updated(changed: 1) () pure {}
require_updated(changed: other) () pure {
fail(dever.api.Error.Conflict)
}
```
## require_content
文章字段规范化、分页边界和发布状态规则集中在纯 Domain。
- 函数:`require_content`
- 输入:
- `slug: Text`:规范化标识
- `title: Text`:文章标题
- `body: Text`:正文
- 输出:无
```dever
require_content(slug: Text, title: Text, body: Text) () pure {
require_valid(slug != "" and title != "" and text.trim(body) != "")
}
```
## require_valid
文章字段规范化、分页边界和发布状态规则集中在纯 Domain。
- 函数:`require_valid`
- 输入:
- `valid: Bool`:该声明的业务值
- 输出:无
```dever
require_valid(valid: true) () pure {}
require_valid(valid: false) () pure {
fail(dever.api.Error.Invalid)
}
```
@@ -0,0 +1,86 @@
# 文章模型
草稿位于租户数据库,REST 由可信用户 owner 限定到作者范围。
- 包:`news.article.model`
- 公开类型:
- `ArticleStatus`
- `Article`
- 公开方法:无
- 使用:无
## 文章状态
本节定义对应的源码合同。
- 类型:`ArticleStatus`
- 分支:
- `Draft`:该声明的业务值
- `Published`:该声明的业务值
```dever
type ArticleStatus {
Draft = "草稿"
Published = "已发布"
}
```
## 文章记录
本节定义对应的源码合同。
- 类型:`Article`
- 字段:
- `private author_id: user.account.model.principal.id`:可信作者标识
- `slug: Text(1, 180)`:规范化标识
- `title: Text(1, 160)`:文章标题
- `body: Text`:正文
- `category_id: content.category.model.id?`:可选分类引用
- `asset_id: media.asset.model.id?`:可选媒体引用
- `private version: Int`:当前编辑版本
- `private status: ArticleStatus`:业务状态
- `private published_at: DateTime?`:实际发布时间
```dever
type Article {
private owner author_id: user.account.model.principal.id = dever.auth.user_id()
slug: Text(1, 180) unique
title: Text(1, 160)
body: Text
category_id: content.category.model.id?
asset_id: media.asset.model.id?
private version: Int default 1
private status: ArticleStatus default ArticleStatus.Draft index
private published_at: DateTime?
}
```
## 作者索引
本节定义对应的源码合同。
- 声明:`index(author_id, created_at)`
```dever
index(author_id, created_at)
```
## sql owned_articles
草稿位于租户数据库,REST 由可信用户 owner 限定到作者范围。
- 声明:`sql owned_articles`
- 输入:
- `author: user.account.model.principal.id`:该声明的业务值
- `size: Int`:受限页大小
- 输出:
- `articles: List<app.ArticleView>`:该声明的业务值
```dever
sql owned_articles(author: user.account.model.principal.id, size: Int) (
articles: List<app.ArticleView>
) {
sqlite = "SELECT id, slug, title, body, version, category_id, asset_id FROM article WHERE author_id = ?1 ORDER BY id DESC LIMIT ?2"
postgres = "SELECT id, slug, title, body, version, category_id, asset_id FROM article WHERE author_id = $1 ORDER BY id DESC LIMIT $2"
}
```
@@ -0,0 +1,29 @@
# 文章公开读模型
发布动作把可公开内容写入无私密字段的租户内读模型。
- 包:`news.article.model.publication`
- 公开类型:
- `Publication`
- 公开方法:无
- 使用:无
## 发布记录
本节定义对应的源码合同。
- 类型:`Publication`
- 字段:
- `slug: Text(1, 180)`:文章标识
- `title: Text(1, 160)`:标题
- `body: Text`:正文
- `published_at: DateTime`:发布时间
```dever
type Publication {
slug: Text(1, 180) unique
title: Text(1, 160)
body: Text
published_at: DateTime index
}
```