Nuda Kit uses a decoupled architecture. The frontend and backend are completely separate applications that can be developed, tested, and deployed independently. They communicate strictly via HTTP requests (REST API).
┌─────────────────────────────────────────────────────────────────────────┐
│ Client (Browser) │
└─────────────────────────────────┬───────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ Frontend (Nuxt 4) │
│ localhost:3000 │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Pages │ │Components│ │ Stores │ │ Services │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────┬───────────────────────────────────────┘
│ REST API
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ Backend (AdonisJS v6) │
│ localhost:3333 │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Routes │ │Controllers│ │ Services │ │ Models │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
└───────┬─────────────────────────┬───────────────────────┬───────────────┘
│ │ │
▼ ▼ ▼
┌───────────────┐ ┌─────────────────┐ ┌───────────────┐
│ PostgreSQL │ │ Redis │ │ Stripe │
│ Database │ │ Queues │ │ Payments │
└───────────────┘ └─────────────────┘ └───────────────┘
Client (Browser)
Frontend (Nuxt)
Backend (AdonisJS)
Infrastructure
When a user performs an action like "Create Team", here's what happens:
User clicks "Create Team" button in the Nuxt UI.
The frontend sends a POST /teams request to the AdonisJS server using TanStack Query.
AdonisJS validates the request payload using VineJS. Invalid requests return a 422 error immediately.
Bouncer checks if the user has permission to create a team (e.g., subscription limits).
The controller creates the team record in PostgreSQL and associates the user as the owner.
AdonisJS returns the created team as JSON with a 201 status code.
TanStack Query receives the response, invalidates the teams cache, and the UI updates automatically.
In development, you run two separate servers:
| Service | Port | URL | Description |
|---|---|---|---|
| Nuxt | 3000 | http://localhost:3000 | Frontend server - visit this in your browser |
| AdonisJS | 3333 | http://localhost:3333 | API server - Nuxt communicates with this |
NUXT_PUBLIC_API_BASE_URL environment variable points to the backend server URL.The codebase is organized into three main directories:
nuda-kit/
├── frontend/ # Nuxt 4 Application
├── backend/ # AdonisJS v6 Application
└── etc/
└── docker/ # Docker Compose & configs
frontend/
├── app/
│ ├── assets/ # CSS, images, brand logos
│ ├── components/ # Vue components (shadcn-vue + custom)
│ │ ├── app/ # Application-specific components
│ │ ├── landing/ # Landing page components
│ │ └── ui/ # shadcn-vue primitives
│ ├── composables/ # Vue composables
│ │ └── queries/ # TanStack Query hooks
│ ├── layouts/ # Page layouts (app, auth, settings)
│ ├── middleware/ # Route middleware (auth, guest)
│ ├── pages/ # File-based routing
│ │ ├── app/ # Authenticated app pages
│ │ │ ├── auth/ # Login, signup, forgot password
│ │ │ └── settings/ # User & team settings
│ │ └── index.vue # Landing page
│ ├── plugins/ # Nuxt plugins
│ ├── services/api/ # API service functions
│ ├── stores/ # Pinia stores
│ └── types/ # TypeScript type definitions
├── public/ # Static assets
└── nuxt.config.ts # Nuxt configuration
backend/
├── app/
│ ├── abilities/ # Bouncer ability definitions
│ ├── controllers/ # HTTP controllers (by domain)
│ │ ├── ai/ # AI streaming endpoints
│ │ ├── billing/ # Stripe checkout & portal
│ │ ├── invitations/ # Team invitation handling
│ │ ├── plans/ # Subscription plans
│ │ ├── teams/ # Team CRUD & members
│ │ ├── users/ # Auth & user management
│ │ └── webhooks/ # Stripe webhooks
│ ├── events/ # Event dispatchers
│ ├── exceptions/ # Custom exception handlers
│ ├── jobs/ # Background jobs (BullMQ)
│ ├── listeners/ # Event listeners
│ ├── mails/ # Email notifications
│ ├── middleware/ # HTTP middleware
│ ├── models/ # Lucid ORM models
│ ├── policies/ # Bouncer authorization policies
│ ├── services/ # Business logic services
│ └── validators/ # VineJS validation schemas
├── config/ # Configuration files
├── database/
│ ├── migrations/ # Database migrations
│ └── seeders/ # Database seeders
├── resources/views/emails/ # Edge email templates
├── start/
│ ├── routes/ # Route definitions (by domain)
│ ├── events.ts # Event bindings
│ ├── kernel.ts # Middleware stack
│ └── limiter.ts # Rate limiting rules
├── tests/ # Japa test suites
└── adonisrc.ts # AdonisJS configuration
The backend API is organized into logical domains:
| Domain | Prefix | Description |
|---|---|---|
| Users | /users | Authentication, profile, avatar |
| Teams | /teams | Team CRUD, members, invitations |
| Invitations | /invitations | Accept/reject invitations |
| Billing | /billing | Stripe checkout, portal, invoices |
| Plans | /plans | Subscription plan listing |
| AI | /ai | AI chat streaming |
| Webhooks | /webhooks | Stripe webhook handler |
| Docs | /docs | Swagger API documentation |
CreateTeamController), making code easy to find, test, and maintain.