mcpField
A
adonisjs

adonisjs

github.com/lncitadorDevelopment744 installsUpdated 25w ago
Repository

About adonisjs

adonisjs is a skill for developers building AdonisJS backends. It provides framework conventions, workflows, and references for common application tasks, with database and ORM work explicitly delegated to the separate lucid skill.

Key features

  1. 01AdonisJS routing and controller guidance
  2. 02Validation and transformer conventions
  3. 03Workflow guides for features and debugging
  4. 04References for auth, HTTP, queues, and security
  5. 05Ace CLI command examples

Use cases

  1. 01Implementing an AdonisJS feature
  2. 02Reviewing routes and controller structure
  3. 03Debugging framework behavior

Install

Copy the command and run it in a terminal.

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

After installing, type/adonisjsin Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with 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

Details

From the project README

AdonisJS Backend Skill

Boundary With Lucid

This skill covers the AdonisJS framework layer. Load lucid for database and ORM work:

  • Migrations and schema generation
  • database/schema.ts
  • Model files and model hooks/scopes/serialization
  • Relationships and preloads
  • Query builders and transactions
  • Factories and seeders

AdonisJS controllers, transformers, policies, and services may consume Lucid models, but the rules for defining/querying those models live in lucid.


Core Conventions

Routing (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())
Controllers (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 })
  }
}
Transformers (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())
Validation (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()
)

Critical Import Rules

// 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

SituationFile
Implementing any new featureworkflows/build-feature.md
Debugging errors, unexpected behaviorworkflows/debug.md
Creating Service Providers, bindings, IoCworkflows/providers.md
Customizing errors, domain exceptionsworkflows/exceptions.md
Decoupling side effects with eventsworkflows/events.md
Reviewing a PR or code snippetworkflows/code-review.md

References

TopicFile
Architecture, folder structure, three rendering modesreferences/architecture.md
Auth, guards, Bouncer (.authorize vs .allows)references/auth.md
Cache, invalidation, TTL, tagsreferences/cache.md
Controllers, resource vs action, route orderingreferences/controllers.md
Events, listeners, emitterreferences/events.md
Exceptions handler, custom domain errorsreferences/exceptions.md
HTTP — request, response, session, URL builderreferences/http.md
Mail — send, mail classes, templates, testingreferences/mail.md
Middleware — named, params, globalreferences/middleware.md
Performance — cache, queues, deferred expensive workreferences/performance.md
Queue, jobs, retry, workersreferences/queue.md
Security — hashing, encryption, CORS, CSRFreferences/security.md
Transformers — BaseTransformer, pick, whenLoaded, variantsreferences/transformers.md
VineJS validations — vine.create(), all field typesreferences/validations.md
Ace commands — create, args, flags, promptsreferences/ace-commands.md

Ace CLI Quick Reference

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

Anti-Patterns

WrongCorrect
vine.compile()vine.create()
Inline validation in controllerSeparate app/validators/ file
Business logic in controllerMove to app/services/
Side effects (email) in controllerEvents + Listeners
import from '@adonisjs/core' directlySub-path: '@adonisjs/core/http' etc.
8+ methods on one controllerSplit into focused Action controllers
Email verification behind auth middlewareVerification routes must be public
Dynamic route (:id) before fixed route (/create)Fixed routes first
bouncer.authorize() in transformersbouncer.allows() in transformers
router.makeUrl()urlFor() from @adonisjs/core/services/url_builder
{{ route('...') }} in Edge{{ urlFor('...') }} in Edge
Missing prefixUrl in signedUrlFor for emailsAlways pass prefixUrl for external links

Comments

Markdown supported