@eyjs/create-app
v1.0.0
Published
CLI tool to generate hexagonal folder structure for EyJS applications
Maintainers
Readme
@eyjs/create-app
CLI tool to generate hexagonal architecture folder structure for EyJS applications. Quickly scaffold new projects with domain-driven design principles and clean architecture patterns.
Features
- 🏗️ Hexagonal Architecture - Generates clean architecture folder structure
- 🎯 Domain-Driven Design - Follows DDD principles with proper separation of concerns
- 📁 Automated Scaffolding - Creates all necessary files and folders automatically
- 🔧 TypeScript Support - Full TypeScript setup with proper type definitions
- ⚡ Zero Configuration - Works out of the box with sensible defaults
- 🎨 Customizable Templates - Flexible template system for different project types
Installation
# Using Bun (recommended)
bun add -g @eyjs/create-app
# Using npm
npm install -g @eyjs/create-app
# Using yarn
yarn global add @eyjs/create-app
# Using pnpm
pnpm add -g @eyjs/create-appQuick Start
# Create a new EyJS application
create-eyjs-app my-awesome-app
# Create app in a specific directory
create-eyjs-app my-app --path ./projects
# Create with custom template
create-eyjs-app my-app --template apiGenerated Structure
The CLI generates a complete hexagonal architecture structure:
my-app/
├── application/ # Application layer
│ ├── services/
│ │ └── my-app.service.ts # Main application service
│ ├── dtos/
│ │ └── create-my-app.dto.ts # Data transfer objects
│ └── interfaces/
│ └── my-app.repository.interface.ts
├── domain/ # Domain layer
│ ├── entities/
│ │ └── my-app.entity.ts # Domain entity
│ ├── value-objects/
│ │ └── id.value-object.ts # Value objects
│ ├── events/
│ │ └── my-app-created.event.ts
│ └── interfaces/
│ └── my-app.repository.interface.ts
├── infrastructure/ # Infrastructure layer
│ ├── controllers/
│ │ └── my-app.controller.ts # HTTP controllers
│ ├── repositories/
│ │ └── my-app-mongo.repository.ts # Database implementations
│ ├── middleware/
│ │ └── validation.middleware.ts
│ └── config/
│ └── database.config.ts
├── shared/ # Shared utilities
│ ├── errors/
│ ├── types/
│ └── utils/
├── tests/ # Test files
│ ├── unit/
│ ├── integration/
│ └── e2e/
├── package.json
├── tsconfig.json
├── .env.example
└── README.mdCommand Line Options
create-eyjs-app <app-name> [options]
Options:
--path <path> Specify the directory to create the app
--template <name> Choose a template (api, web, microservice)
--skip-install Skip dependency installation
--help Show help information
--version Show version informationAvailable Templates
| Template | Description | Use Case |
|----------|-------------|----------|
| api | REST API with controllers | Backend APIs, microservices |
| web | Full-stack web application | Web applications with frontend |
| microservice | Microservice with event bus | Event-driven microservices |
Generated Files
Application Layer
Service (application/services/my-app.service.ts)
import { Injectable } from '@eyjs/core'
import { MyAppRepository } from '../interfaces/my-app.repository.interface'
import { CreateMyAppDto } from '../dtos/create-my-app.dto'
@Injectable()
export class MyAppService {
constructor(private readonly repository: MyAppRepository) {}
async create(dto: CreateMyAppDto) {
// Business logic implementation
}
async findById(id: string) {
// Find by ID logic
}
}DTO (application/dtos/create-my-app.dto.ts)
export interface CreateMyAppDto {
name: string
description?: string
// Additional fields
}Domain Layer
Entity (domain/entities/my-app.entity.ts)
import { IdValueObject } from '../value-objects/id.value-object'
export class MyAppEntity {
constructor(
public readonly id: IdValueObject,
public readonly name: string,
public readonly description?: string
) {}
static create(name: string, description?: string) {
return new MyAppEntity(
IdValueObject.generate(),
name,
description
)
}
}Value Object (domain/value-objects/id.value-object.ts)
import { v4 as uuidv4 } from 'uuid'
export class IdValueObject {
constructor(private readonly value: string) {
if (!this.isValid(value)) {
throw new Error('Invalid ID format')
}
}
static generate(): IdValueObject {
return new IdValueObject(uuidv4())
}
toString(): string {
return this.value
}
private isValid(value: string): boolean {
// UUID validation logic
return true
}
}Infrastructure Layer
Controller (infrastructure/controllers/my-app.controller.ts)
import { Controller, Get, Post } from '@eyjs/http-server'
import { MyAppService } from '../../application/services/my-app.service'
import { CreateMyAppDto } from '../../application/dtos/create-my-app.dto'
@Controller('/my-app')
export class MyAppController {
constructor(private readonly service: MyAppService) {}
@Post()
async create(dto: CreateMyAppDto) {
return await this.service.create(dto)
}
@Get('/:id')
async findById(id: string) {
return await this.service.findById(id)
}
}Repository (infrastructure/repositories/my-app-mongo.repository.ts)
import { Injectable } from '@eyjs/core'
import { MyAppRepository } from '../../domain/interfaces/my-app.repository.interface'
import { MyAppEntity } from '../../domain/entities/my-app.entity'
@Injectable()
export class MyAppMongoRepository implements MyAppRepository {
async save(entity: MyAppEntity): Promise<void> {
// MongoDB implementation
}
async findById(id: string): Promise<MyAppEntity | null> {
// MongoDB find implementation
}
}Configuration Files
Package.json
{
"name": "my-app",
"version": "1.0.0",
"type": "module",
"scripts": {
"dev": "bun run --watch src/index.ts",
"build": "tsc",
"start": "bun run src/index.ts",
"test": "bun test"
},
"dependencies": {
"@eyjs/core": "^1.0.4"
},
"devDependencies": {
"@types/node": "^20.0.0",
"typescript": "^5.0.0"
}
}TypeScript Configuration
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "node",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
"@/application/*": ["./src/application/*"],
"@/domain/*": ["./src/domain/*"],
"@/infrastructure/*": ["./src/infrastructure/*"]
}
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}Usage Examples
Creating Different Types of Applications
# REST API
create-eyjs-app user-api --template api
# Web Application
create-eyjs-app ecommerce-web --template web
# Microservice
create-eyjs-app notification-service --template microserviceCustom Directory Structure
# Create in specific path
create-eyjs-app my-app --path ./backend-services
# Result: ./backend-services/my-app/Skip Installation
# Generate files without installing dependencies
create-eyjs-app my-app --skip-installIntegration with EyJS
The generated applications are fully compatible with the EyJS ecosystem:
// Generated app automatically includes EyJS core
import { EyJs } from '@eyjs/core'
// Dependency injection works out of the box
@Injectable()
export class MyService {
// Auto-injected dependencies
}
// HTTP server integration
import { Controller, Get } from '@eyjs/http-server'
@Controller('/api')
export class ApiController {
// HTTP endpoints
}Best Practices
Domain-Driven Design
- Keep business logic in the domain layer
- Use value objects for complex data types
- Implement domain events for side effects
Clean Architecture
- Dependencies point inward (toward domain)
- Use interfaces for external dependencies
- Keep infrastructure concerns separate
Testing Strategy
- Unit tests for domain logic
- Integration tests for repositories
- E2E tests for API endpoints
Contributing
Contributions are welcome! Please read our Contributing Guide for details.
License
This project is licensed under the MIT License - see the LICENSE file for details.
