Project Structure

Learn how to organize your MoroJS projects for scalability and maintainability. From simple APIs to enterprise applications.

Basic Project Structure

Simple API Structure (Based on Actual Examples)

typescript

1simple-api/
2├── src/
3│   └── server.ts          # Main application entry (single file)
4├── package.json
5├── package-lock.json
6├── tsconfig.json
7└── README.md
8
9# Example from actual simple-api implementation:
10# - Single server.ts file with all routes
11# - In-memory data storage
12# - Zod schemas defined inline
13# - Simple, focused structure
14
15# Content of src/server.ts:
16import { createApp, z } from '@morojs/moro';
17
18const app = createApp();
19
20const UserSchema = z.object({
21  name: z.string().min(2).max(50),
22  email: z.string().email(),
23  age: z.number().min(18).optional()
24});
25
26// Routes and logic in single file
27app.get('/', (req, res) => { /* ... */ });
28app.get('/users', (req, res) => { /* ... */ });
29app.post('/users').body(UserSchema).handler((req, res) => { /* ... */ });
30
31app.listen(3001);

Modular Structure (Recommended)

For larger applications, use functional modules for better organization:

Real-time Chat Structure (Actual Example)

typescript

1real-time-chat/
2├── src/
3│   ├── server.ts          # Main server with WebSocket
4│   ├── services/          # Service layer
5│   │   ├── AuthService.ts
6│   │   └── ChatService.ts
7│   └── controllers/       # (empty in actual implementation)
8├── database/              # Database setup (if needed)
9├── test-client.html       # WebSocket test client
10├── package.json
11├── package-lock.json
12├── tsconfig.json
13└── README.md
14
15# Key features in actual implementation:
16# - WebSocket support with app.websocket()
17# - Simple authentication endpoints
18# - In-memory storage for demo
19# - Services for chat functionality

Enterprise Project Structure (Actual Implementation)

typescript

1enterprise-app/
2├── src/
3│   ├── server.ts          # Main application bootstrap
4│   └── modules/           # Functional modules
5│       ├── users/
6│       │   ├── index.ts   # Module definition
7│       │   ├── routes.ts  # Route handlers
8│       │   ├── sockets.ts # WebSocket handlers
9│       │   ├── actions.ts # Business logic
10│       │   ├── schemas.ts # Zod schemas
11│       │   ├── types.ts   # TypeScript types
12│       │   └── config.ts  # Module config
13│       ├── orders/
14│       │   ├── index.ts
15│       │   ├── routes.ts
16│       │   ├── actions.ts
17│       │   └── types.ts
18│       ├── todos/
19│       │   ├── index.ts
20│       │   ├── routes.ts
21│       │   ├── actions.ts
22│       │   └── types.ts
23│       └── health/
24│           └── index.ts
25├── package.json
26├── package-lock.json
27├── tsconfig.json
28└── README.md
29
30# Key differences from complex documentation:
31# - Functional module architecture (no decorators)
32# - defineModule() instead of createModule()
33# - Pure actions.ts for business logic
34# - Simple routes.ts with function definitions
35# - No complex shared/config directories

Functional Module Example (Actual Implementation)

typescript

1// src/modules/users/index.ts - Functional Module Definition
2import { defineModule } from '@morojs/moro';
3import { routes } from './routes';
4import { sockets } from './sockets';
5import * as actions from './actions';
6import * as types from './types';
7
8export default defineModule({
9  name: 'users',
10  version: '1.0.0',
11  prefix: '/api/v1.0.0/users',
12  
13  // Register routes (functional approach)
14  routes,
15  
16  // Register WebSocket handlers
17  sockets,
18  
19  // Export module actions and types
20  actions,
21  types,
22  
23  // Module lifecycle hooks
24  onLoad: async (app) => {
25    console.log('👥 Users module loaded');
26  },
27  
28  onUnload: async (app) => {
29    console.log('👥 Users module unloaded');
30  }
31});
32
33// src/server.ts - Main application
34import { createApp } from '@morojs/moro';
35import UsersModule from './modules/users';
36import OrdersModule from './modules/orders';
37import HealthModule from './modules/health';
38
39async function createEnterpriseApp() {
40  const app = createApp({
41    cors: true,
42    compression: true,
43    helmet: true
44  });
45
46  // Register mock database
47  const mockDatabase = {
48    users: [
49      { id: 1, name: 'John Doe', email: 'john@example.com', role: 'admin' }
50    ]
51  };
52  app.database(mockDatabase);
53
54  // Load functional modules
55  await app.loadModule(HealthModule);
56  await app.loadModule(UsersModule);
57  await app.loadModule(OrdersModule);
58
59  return app;
60}
61
62const app = await createEnterpriseApp();
63app.listen(3002);

Configuration Files

package.json

package.json (Based on Actual Examples)

typescript

1{
2  "name": "simple-api-example",
3  "version": "1.0.0",
4  "private": true,
5  "description": "Simple API demonstration showing basic Moro framework usage",
6  "main": "src/server.ts",
7  "scripts": {
8    "dev": "NODE_ENV=development ts-node src/server.ts",
9    "dev:watch": "NODE_ENV=development ts-node-dev --respawn --transpile-only src/server.ts",
10    "build": "tsc",
11    "start": "NODE_ENV=production node dist/server.js",
12    "test": "echo "No tests specified"",
13    "switch:local": "rm -rf node_modules package-lock.json && npm install file:../../MoroJS",
14    "switch:npm": "rm -rf node_modules package-lock.json && npm install @morojs/moro@latest"
15  },
16  "dependencies": {
17    "@morojs/moro": "file:../../MoroJS"
18  },
19  "devDependencies": {
20    "@types/node": "^20.10.0",
21    "ts-node": "^10.9.1",
22    "ts-node-dev": "^2.0.0",
23    "typescript": "^5.3.2"
24  },
25  "keywords": [
26    "moro",
27    "api",
28    "simple",
29    "example"
30  ]
31}

tsconfig.json

tsconfig.json (From Actual Examples)

typescript

1{
2  "compilerOptions": {
3    "target": "ES2020",
4    "lib": ["ES2020"],
5    "module": "commonjs",
6    "moduleResolution": "node",
7    "esModuleInterop": true,
8    "allowSyntheticDefaultImports": true,
9    "strict": true,
10    "skipLibCheck": true,
11    "forceConsistentCasingInFileNames": true,
12    "outDir": "./dist",
13    "rootDir": "./src",
14    "declaration": true,
15    "declarationMap": true,
16    "sourceMap": true,
17    "experimentalDecorators": true,
18    "emitDecoratorMetadata": true,
19    "resolveJsonModule": true
20  },
21  "include": [
22    "src/**/*"
23  ],
24  "exclude": [
25    "node_modules",
26    "dist"
27  ]
28}

Organization Best Practices

File Organization

  • Group related functionality in modules
  • Keep schemas close to their usage
  • Separate business logic from routes
  • Use consistent naming conventions

Code Organization

  • Export modules from index files
  • Use TypeScript path mapping
  • Keep configuration centralized
  • Document your structure

Next Steps