mcpField
A
adonisjs

adonisjs

github.com/lncitador開発744 回インストール25 週間前に更新
リポジトリ

adonisjs について

adonisjs は、AdonisJS のバックエンド開発者向けスキルです。フレームワークの規約や作業手順、各種リファレンスを提供し、データベースと ORM の作業は別の lucid スキルに委ねます。

主な機能

  1. 01AdonisJS のルーティングとコントローラーの指針
  2. 02バリデーションとトランスフォーマーの規約
  3. 03機能開発とデバッグの手順
  4. 04認証、HTTP、キュー、セキュリティの資料
  5. 05Ace CLI コマンド例

活用シーン

  1. 01AdonisJS の機能実装
  2. 02ルートとコントローラー構成の確認
  3. 03フレームワーク動作のデバッグ

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/lncitador/adonisjs-maestro --skill adonisjs

インストール後、Claude Code で/adonisjsを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

agents/
openai.yaml
references/
ace-commands.md
architecture.md
auth.md
cache.md
controllers.md
events.md
exceptions.md
http.md
mail.md
middleware.md
performance.md
queue.md
security.md
transformers.md
validations.md
workflows/
build-feature.md
code-review.md
debug.md
events.md
exceptions.md
providers.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

リファレンス

トピックファイル
アーキテクチャ、フォルダー構成、3 つのレンダリングモード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、CSRFreferences/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' などのサブパスを使う
1 つのコントローラーに 8 個以上のメソッドを持たせる役割を絞ったアクションコントローラーに分割する
メール認証を認証ミドルウェアの背後に置く認証確認ルートは公開する
固定ルート(/create)より前に動的ルート(:id)を置く固定ルートを先に定義する
トランスフォーマーで bouncer.authorize() を使うトランスフォーマーでは bouncer.allows() を使う
router.makeUrl()@adonisjs/core/services/url_builder の urlFor() を使う
Edge で {{ route('...') }} を使うEdge では {{ urlFor('...') }} を使う
メール用の signedUrlFor で prefixUrl を指定しない外部リンクには必ず prefixUrl を渡す

コメント