Backend Development

Project Structure

How the Nuda Kit backend is organized.

The backend follows standard AdonisJS v6 conventions with some additional patterns specific to Nuda Kit. For general AdonisJS directory structure, see the official AdonisJS documentation.

This page focuses on Nuda Kit-specific patterns you should understand.

Directory Overview

backend/
├── app/
│   ├── abilities/        # Bouncer ability definitions
│   ├── controllers/      # HTTP controllers (by domain)
│   ├── events/           # Event dispatchers
│   ├── exceptions/       # Exception handlers
│   ├── jobs/             # Background jobs (BullMQ)
│   ├── listeners/        # Event listeners
│   ├── mails/            # Email notifications
│   ├── middleware/       # HTTP middleware
│   ├── models/           # Lucid ORM models
│   ├── policies/         # Authorization policies
│   ├── services/         # Business logic services
│   └── validators/       # VineJS validation schemas
├── config/               # Configuration files
├── database/
│   ├── migrations/       # Database migrations
│   └── seeders/          # Database seeders
├── resources/views/      # Edge templates (emails)
├── start/
│   ├── routes/           # Route definitions (by domain)
│   ├── events.ts         # Event bindings
│   ├── kernel.ts         # Middleware stack
│   └── limiter.ts        # Rate limiting rules
└── tests/                # Japa test suites

Key Patterns

Controller-per-Action

Nuda Kit uses a single controller per action pattern instead of resource controllers:

controllers/
└── users/
    ├── create_user_controller.ts       # POST /users
    ├── login_user_controller.ts        # POST /users/login
    ├── get_authenticated_user_controller.ts  # GET /users/me
    └── update_user_detail_controller.ts     # PUT /users

Why? Each controller is small, focused, and easy to test. No scrolling through a 500-line resource controller.

Domain-based Organization

Controllers, routes, and tests are organized by domain:

DomainPurpose
users/Authentication, profile, settings
teams/Team CRUD, members, avatars
invitations/Team invitation handling
billing/Stripe checkout, portal, invoices
plans/Subscription plans
ai/AI streaming endpoints
webhooks/External webhooks (Stripe)

App Directory

controllers/

HTTP controllers organized by domain. Each controller handles one action:

// app/controllers/users/create_user_controller.ts
export default class CreateUserController {
  public async execute({ request, response }: HttpContext) {
    // Handle the request
  }
}

models/

Lucid ORM models representing database tables:

ModelTablePurpose
UserusersUser accounts
TeamteamsTeams/organizations
TeamMemberteam_membersTeam membership with roles
InvitationinvitationsPending team invitations
PlanplansSubscription plans
SubscriptionsubscriptionsUser subscriptions

validators/

VineJS validation schemas organized by domain:

validators/
├── user.ts      # User-related validations
├── team.ts      # Team-related validations
├── billing.ts   # Billing validations
└── ai.ts        # AI request validations

services/

Business logic extracted from controllers:

ServicePurpose
AiServiceAI provider abstraction and streaming
StripeServiceStripe API interactions

events/

Event dispatchers for decoupled side effects:

EventTriggered When
UserCreatedNew user registers
UserDeletedUser account deleted
SendUserVerificationEmailEmail verification needed
SendUserResetPasswordEmailPassword reset requested

listeners/

Event listeners that respond to dispatched events:

ListenerResponds To
CreateTeamUserCreated — creates default team
SendVerificationEmailSendUserVerificationEmail
SendPasswordResetEmailSendUserResetPasswordEmail
EnqueueDeleteUserUserDeleted — queues deletion job

jobs/

Background jobs processed by BullMQ:

JobPurpose
SendVerificationEmailJobSend verification email
SendMagicLinkEmailJobSend magic link email
SendResetPasswordEmailJobSend password reset email
SendInvitationEmailJobSend team invitation email
DeleteUserJobPermanently delete user data

mails/

Email notification classes:

MailPurpose
VerifyEmailNotificationEmail verification
MagicLinkEmailNotificationMagic link login
ResetPasswordEmailNotificationPassword reset
InvitationEmailNotificationTeam invitation

policies/

Bouncer authorization policies:

PolicyControls
TeamPolicyTeam access (update, delete, manage members)

middleware/

HTTP middleware in the request pipeline:

MiddlewarePurpose
AuthMiddlewareVerify authentication
ForceJsonResponseMiddlewareAlways return JSON
InitializeBouncerMiddlewareSetup authorization
SwaggerAuthMiddlewareProtect API docs

Start Directory

routes/

Route definitions split by domain:

start/routes/
├── users.ts        # /users/*
├── teams.ts        # /teams/*
├── invitations.ts  # /invitations/*
├── billing.ts      # /billing/*
├── plans.ts        # /plans/*
├── ai.ts           # /ai/*
├── webhooks.ts     # /webhooks/*
└── docs.ts         # /docs (Swagger)

events.ts

Binds events to their listeners:

emitter.on(UserCreated, [CreateTeam])
emitter.on(SendUserVerificationEmail, [SendVerificationEmail])

kernel.ts

Defines the middleware stack and named middleware.

limiter.ts

Rate limiting rules for specific routes.


Config Directory

Key configuration files:

ConfigPurpose
auth.tsAuthentication guards
database.tsPostgreSQL connection
mail.tsEmail providers (SMTP, Mailgun, Resend)
drive.tsFile storage (local, S3)
queue.tsRedis queue configuration
ally.tsSocial auth providers
swagger.tsAPI documentation

Database Directory

migrations/

Database migrations in chronological order:

  • Users and access tokens
  • Email verification tokens
  • Password reset tokens
  • Teams and team members
  • Invitations
  • Subscriptions and plans

seeders/

Database seeders for development and testing:

SeederPurpose
PlanSeederCreate subscription plans
tests/*Test data seeders

Tests Directory

Tests mirror the controller structure:

tests/functional/
├── users/           # User endpoint tests
├── teams/           # Team endpoint tests
├── billing/         # Billing endpoint tests
├── invitations/     # Invitation endpoint tests
├── plans/           # Plans endpoint tests
└── webhooks/        # Webhook tests

File Naming Conventions

TypeConventionExample
Controllerssnake_case_controller.tscreate_user_controller.ts
Modelssnake_case.tsteam_member.ts
Migrationstimestamp_description.ts1756568731173_create_users_table.ts
Jobssnake_case_job.tssend_verification_email_job.ts
Eventssnake_case.tsuser_created.ts
Validatorssnake_case.tsuser.ts

Import Aliases

Nuda Kit uses import aliases for clean imports:

import User from '#models/user'
import { createUserValidator } from '#validators/user'
import CreateUserController from '#controllers/users/create_user_controller'
import SendVerificationEmailJob from '#jobs/send_verification_email_job'

Available aliases are defined in package.json under imports.

Resources