关于 adonisjs
adonisjs 是面向 AdonisJS 后端开发者的技能,提供框架约定、常见任务工作流和参考资料,并明确将数据库与 ORM 工作交由独立的 lucid 技能处理。
主要功能
- 01AdonisJS 路由与控制器指南
- 02验证器与转换器约定
- 03功能开发和调试工作流
- 04认证、HTTP、队列与安全参考
- 05Ace CLI 命令示例
适用场景
- 01实现 AdonisJS 功能
- 02检查路由和控制器结构
- 03调试框架行为
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ lncitador/ adonisjs-maestro --skill adonisjs安装后在 Claude Code 中输入/adonisjs确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
agents/openai.yamlreferences/ace-commands.mdarchitecture.mdauth.mdcache.mdcontrollers.mdevents.mdexceptions.mdhttp.mdmail.mdmiddleware.mdperformance.mdqueue.mdsecurity.mdtransformers.mdvalidations.mdworkflows/build-feature.mdcode-review.mddebug.mdevents.mdexceptions.mdproviders.md详细介绍
AdonisJS 后端技能
与 Lucid 的边界
此技能涵盖 AdonisJS 框架层。数据库和 ORM 相关工作请加载 lucid:
- 迁移和架构生成
database/schema.ts- 模型文件以及模型钩子/作用域/序列化
- 关系和预加载
- 查询构建器和事务
- 工厂和种子器
AdonisJS 控制器、转换器、策略和服务可以使用 Lucid 模型,但模型的定义和查询规则属于 lucid。
核心约定
路由(start/routes.ts)
import router from '@adonisjs/core/services/router'
import { middleware } from '#start/kernel'
import { controllers } from '#generated/controllers'
// CRITICAL: fixed routes BEFORE dynamic params
router.get('/posts/create', [controllers.Posts, 'create']).use(middleware.auth())
router.post('/posts', [controllers.Posts, 'store']).use(middleware.auth())
router.get('/posts/:id', [controllers.Posts, 'show'])
router.get('/posts/:id/edit', [controllers.Posts, 'edit']).use(middleware.auth())
router.put('/posts/:id', [controllers.Posts, 'update']).use(middleware.auth())
// Guest-only
router.group(() => {
router.get('/login', [controllers.Session, 'create'])
router.post('/login', [controllers.Session, 'store'])
}).use(middleware.guest())
控制器(app/controllers/)
import type { HttpContext } from '@adonisjs/core/http'
import PostTransformer from '#transformers/post_transformer'
import PostPolicy from '#policies/post_policy'
import { createPostValidator } from '#validators/post'
import postsService from '#services/posts_service'
export default class PostsController {
async index({ inertia }: HttpContext) { // swap inertia for view/serialize per architecture
const posts = await postsService.listForIndex()
return inertia.render('posts/index', { posts: PostTransformer.transform(posts) })
}
async store({ request, auth, response }: HttpContext) {
const payload = await request.validateUsing(createPostValidator)
await postsService.create(auth.user!, payload)
return response.redirect().toRoute('posts.index')
}
async update({ bouncer, params, request, response, session }: HttpContext) {
const post = await postsService.findForUpdate(params.id)
await bouncer.with(PostPolicy).authorize('edit', post) // throws 403 if denied
const data = await request.validateUsing(updatePostValidator)
await postsService.update(post, data)
session.flash('success', 'Post updated successfully')
return response.redirect().toRoute('posts.show', { id: post.id })
}
}
转换器(app/transformers/)
import { BaseTransformer } from '@adonisjs/core/transformers'
import { inject } from '@adonisjs/core'
import { HttpContext } from '@adonisjs/core/http'
import type Post from '#models/post'
import PostPolicy from '#policies/post_policy'
export default class PostTransformer extends BaseTransformer<Post> {
toObject() {
return {
...this.pick(this.resource, ['id', 'title', 'url', 'summary', 'createdAt']),
author: UserTransformer.transform(this.resource.author),
// whenLoaded() — omits field if relation was not preloaded
comments: CommentTransformer.transform(this.whenLoaded(this.resource.comments)),
}
}
// Variant — extends toObject() with permission flags
@inject()
async forDetailedView({ bouncer }: HttpContext) {
return {
...this.toObject(),
can: {
edit: await bouncer.with(PostPolicy).allows('edit', this.resource),
delete: await bouncer.with(PostPolicy).allows('delete', this.resource),
},
}
}
}
// Single: PostTransformer.transform(post)
// Array: PostTransformer.transform(posts)
// Variant: PostTransformer.transform(post).useVariant('forDetailedView')
// Paginated: PostTransformer.paginate(posts.all(), posts.getMeta())
验证(app/validators/)
import vine from '@vinejs/vine'
// vine.create() — not vine.compile()
export const createPostValidator = vine.create({
title: vine.string().trim().minLength(3).maxLength(255),
url: vine.string().url(),
summary: vine.string().trim().minLength(80).maxLength(500),
})
// Clone schema to reuse rules for update
export const updatePostValidator = vine.create(
createPostValidator.schema.clone()
)
关键导入规则
// WRONG — never import from root package
import { HttpContext } from '@adonisjs/core'
// CORRECT sub-path imports
import type { HttpContext } from '@adonisjs/core/http'
import { inject } from '@adonisjs/core'
import { BaseTransformer } from '@adonisjs/core/transformers'
import { BasePolicy } from '@adonisjs/bouncer'
import router from '@adonisjs/core/services/router'
import { urlFor, signedUrlFor } from '@adonisjs/core/services/url_builder'
import vine from '@vinejs/vine'
import Post from '#models/post'
import { controllers } from '#generated/controllers'
工作流
| 情况 | 文件 |
|---|---|
| 实现任何新功能 | workflows/build-feature.md |
| 调试错误或意外行为 | workflows/debug.md |
| 创建服务提供者、绑定、IoC | workflows/providers.md |
| 自定义错误和领域异常 | workflows/exceptions.md |
| 通过事件解耦副作用 | workflows/events.md |
| 审查 PR 或代码片段 | workflows/code-review.md |
参考资料
| 主题 | 文件 |
|---|---|
| 架构、文件夹结构、三种渲染模式 | references/architecture.md |
| 身份验证、守卫、Bouncer(.authorize 与 .allows) | references/auth.md |
| 缓存、失效、TTL、标签 | references/cache.md |
| 控制器、资源与操作、路由顺序 | references/controllers.md |
| 事件、监听器、发射器 | references/events.md |
| 异常处理器、自定义领域错误 | references/exceptions.md |
| HTTP — 请求、响应、会话、URL 构建器 | references/http.md |
| 邮件 — 发送、邮件类、模板、测试 | references/mail.md |
| 中间件 — 命名、参数、全局 | references/middleware.md |
| 性能 — 缓存、队列、延迟执行高开销工作 | references/performance.md |
| 队列、任务、重试、工作进程 | references/queue.md |
| 安全 — 哈希、加密、CORS、CSRF | references/security.md |
| 转换器 — BaseTransformer、pick、whenLoaded、变体 | references/transformers.md |
| VineJS 验证 — vine.create()、所有字段类型 | references/validations.md |
| Ace 命令 — 创建、参数、标志、提示词 | references/ace-commands.md |
Ace CLI 快速参考
node ace make:controller Post --resource
node ace make:validator post
node ace make:transformer post
node ace make:policy post
node ace make:service PostService
node ace make:event OrderPlaced
node ace make:listener SendEmail --event=OrderPlaced
node ace make:job ProcessImage
node ace make:middleware AuthMiddleware
node ace make:exception DomainException
node ace make:command SendReminders
node ace make:mail OrderConfirmation
node ace list:routes
node ace repl
node ace generate:key
# Types in @generated/data are auto-generated by the dev server — no manual command
反模式
| 错误做法 | 正确做法 |
|---|---|
vine.compile() | vine.create() |
| 在控制器中内联验证 | 使用单独的 app/validators/ 文件 |
| 在控制器中编写业务逻辑 | 移至 app/services/ |
| 在控制器中处理副作用(邮件) | 使用事件 + 监听器 |
直接 import from '@adonisjs/core' | 使用子路径:'@adonisjs/core/http' 等 |
| 单个控制器有 8 个或更多方法 | 拆分为职责明确的操作控制器 |
| 在身份验证中间件后配置邮件验证 | 验证路由必须公开 |
将动态路由(:id)放在固定路由(/create)之前 | 固定路由优先 |
在转换器中使用 bouncer.authorize() | 在转换器中使用 bouncer.allows() |
使用 router.makeUrl() | 使用来自 @adonisjs/core/services/url_builder 的 urlFor() |
在 Edge 中使用 {{ route('...') }} | 在 Edge 中使用 {{ urlFor('...') }} |
在邮件的 signedUrlFor 中缺少 prefixUrl | 对外部链接始终传入 prefixUrl |
评论
支持 Markdown