fragment-ts 1.0.17 → 1.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/SETUP.md +570 -0
- package/changes/1.md +420 -0
- package/dist/cli/commands/init.command.js +4 -4
- package/dist/cli/commands/init.command.js.map +1 -1
- package/dist/cli/commands/test.command.d.ts +6 -0
- package/dist/cli/commands/test.command.d.ts.map +1 -0
- package/dist/cli/commands/test.command.js +311 -0
- package/dist/cli/commands/test.command.js.map +1 -0
- package/dist/cli/index.js +6 -3
- package/dist/cli/index.js.map +1 -1
- package/dist/core/container/di-container.d.ts +5 -0
- package/dist/core/container/di-container.d.ts.map +1 -1
- package/dist/core/container/di-container.js +121 -21
- package/dist/core/container/di-container.js.map +1 -1
- package/dist/core/decorators/controller.decorator.js +5 -5
- package/dist/core/decorators/injection.decorators.d.ts +44 -1
- package/dist/core/decorators/injection.decorators.d.ts.map +1 -1
- package/dist/core/decorators/injection.decorators.js +92 -1
- package/dist/core/decorators/injection.decorators.js.map +1 -1
- package/dist/core/metadata/metadata-keys.d.ts +29 -17
- package/dist/core/metadata/metadata-keys.d.ts.map +1 -1
- package/dist/core/metadata/metadata-keys.js +35 -17
- package/dist/core/metadata/metadata-keys.js.map +1 -1
- package/package.json +1 -1
- package/src/cli/commands/init.command.ts +4 -4
- package/src/cli/commands/test.command.ts +289 -0
- package/src/cli/index.ts +16 -11
- package/src/core/container/di-container.ts +166 -31
- package/src/core/decorators/DECORATOR_USAGE.md +326 -0
- package/src/core/decorators/controller.decorator.ts +9 -9
- package/src/core/decorators/injection.decorators.ts +129 -5
- package/src/core/metadata/metadata-keys.ts +44 -18
- package/src/testing/TEST.md +321 -0
package/SETUP.md
ADDED
|
@@ -0,0 +1,570 @@
|
|
|
1
|
+
# Fragment Framework - Complete Setup Guide
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Fragment is a TypeScript framework inspired by Spring Boot that provides:
|
|
6
|
+
- Dependency Injection with decorators
|
|
7
|
+
- TypeORM integration
|
|
8
|
+
- RESTful API support
|
|
9
|
+
- Built-in testing framework
|
|
10
|
+
- CLI tools for development
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install fragment-ts reflect-metadata typeorm
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Project Setup
|
|
19
|
+
|
|
20
|
+
### 1. Initialize Project
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
fragment init
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
This creates:
|
|
27
|
+
```
|
|
28
|
+
project/
|
|
29
|
+
├── src/
|
|
30
|
+
│ ├── app.ts
|
|
31
|
+
│ ├── controllers/
|
|
32
|
+
│ ├── services/
|
|
33
|
+
│ ├── repositories/
|
|
34
|
+
│ └── entities/
|
|
35
|
+
├── fragment.json
|
|
36
|
+
├── tsconfig.json
|
|
37
|
+
└── package.json
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### 2. Configure tsconfig.json
|
|
41
|
+
|
|
42
|
+
```json
|
|
43
|
+
{
|
|
44
|
+
"compilerOptions": {
|
|
45
|
+
"target": "ES2020",
|
|
46
|
+
"module": "commonjs",
|
|
47
|
+
"lib": ["ES2020"],
|
|
48
|
+
"experimentalDecorators": true,
|
|
49
|
+
"emitDecoratorMetadata": true,
|
|
50
|
+
"outDir": "./dist",
|
|
51
|
+
"rootDir": "./src",
|
|
52
|
+
"strict": true,
|
|
53
|
+
"esModuleInterop": true,
|
|
54
|
+
"skipLibCheck": true,
|
|
55
|
+
"forceConsistentCasingInFileNames": true
|
|
56
|
+
},
|
|
57
|
+
"include": ["src/**/*"],
|
|
58
|
+
"exclude": ["node_modules", "dist"]
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### 3. Configure fragment.json
|
|
63
|
+
|
|
64
|
+
```json
|
|
65
|
+
{
|
|
66
|
+
"port": 3000,
|
|
67
|
+
"host": "0.0.0.0",
|
|
68
|
+
"database": {
|
|
69
|
+
"type": "postgres",
|
|
70
|
+
"host": "${DB_HOST:localhost}",
|
|
71
|
+
"port": 5432,
|
|
72
|
+
"username": "${DB_USER:postgres}",
|
|
73
|
+
"password": "${DB_PASSWORD}",
|
|
74
|
+
"database": "${DB_NAME:myapp}",
|
|
75
|
+
"entities": ["dist/**/*.entity.js"],
|
|
76
|
+
"synchronize": false,
|
|
77
|
+
"logging": false
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### 4. Create .env file
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
DB_HOST=localhost
|
|
86
|
+
DB_USER=postgres
|
|
87
|
+
DB_PASSWORD=secret
|
|
88
|
+
DB_NAME=myapp
|
|
89
|
+
EMAIL_FROM=noreply@example.com
|
|
90
|
+
EMAIL_ENABLED=true
|
|
91
|
+
MAX_USERS=1000
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Available Decorators
|
|
95
|
+
|
|
96
|
+
### Class Decorators
|
|
97
|
+
|
|
98
|
+
#### @FragmentApplication
|
|
99
|
+
Application entry point decorator.
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
@FragmentApplication({
|
|
103
|
+
port: 3000,
|
|
104
|
+
host: '0.0.0.0',
|
|
105
|
+
})
|
|
106
|
+
export class App {}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
#### @Controller
|
|
110
|
+
Defines a REST controller.
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
@Controller('/api/users')
|
|
114
|
+
export class UserController {
|
|
115
|
+
// Routes defined here
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
#### @Service
|
|
120
|
+
Business logic layer.
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
@Service()
|
|
124
|
+
export class UserService {
|
|
125
|
+
// Service methods
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
#### @Repository
|
|
130
|
+
Data access layer.
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
@Repository()
|
|
134
|
+
export class UserRepository {
|
|
135
|
+
@InjectRepository(User)
|
|
136
|
+
private repo!: Repository<User>;
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
#### @Injectable
|
|
141
|
+
General purpose injectable component.
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
@Injectable()
|
|
145
|
+
export class EmailService {
|
|
146
|
+
// Utility methods
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
#### @AutoConfiguration
|
|
151
|
+
Auto-configuration component (conditional beans).
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
@AutoConfiguration()
|
|
155
|
+
@ConditionalOnProperty('REDIS_ENABLED', 'true')
|
|
156
|
+
export class RedisConfig {
|
|
157
|
+
// Redis setup
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Property Decorators
|
|
162
|
+
|
|
163
|
+
#### @Autowired
|
|
164
|
+
Automatic dependency injection by type.
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
@Service()
|
|
168
|
+
export class UserService {
|
|
169
|
+
@Autowired()
|
|
170
|
+
private userRepository!: UserRepository;
|
|
171
|
+
|
|
172
|
+
@Autowired()
|
|
173
|
+
private emailService!: EmailService;
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
#### @InjectRepository
|
|
178
|
+
Inject TypeORM repository.
|
|
179
|
+
|
|
180
|
+
```typescript
|
|
181
|
+
@Repository()
|
|
182
|
+
export class UserRepository {
|
|
183
|
+
@InjectRepository(User)
|
|
184
|
+
private userRepo!: Repository<User>;
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
#### @Value
|
|
189
|
+
Inject configuration values from environment.
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
@Service()
|
|
193
|
+
export class AppService {
|
|
194
|
+
@Value('${PORT:3000}')
|
|
195
|
+
private port!: number;
|
|
196
|
+
|
|
197
|
+
@Value('${API_KEY}')
|
|
198
|
+
private apiKey!: string;
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
#### @Inject
|
|
203
|
+
Inject dependency by token.
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
@Service()
|
|
207
|
+
export class MyService {
|
|
208
|
+
@Inject('DATABASE_CONNECTION')
|
|
209
|
+
private db!: DatabaseConnection;
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
#### @Qualifier
|
|
214
|
+
Specify which bean to inject.
|
|
215
|
+
|
|
216
|
+
```typescript
|
|
217
|
+
@Service()
|
|
218
|
+
export class MyService {
|
|
219
|
+
@Qualifier('primary')
|
|
220
|
+
@Autowired()
|
|
221
|
+
private cache!: CacheService;
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Method Decorators
|
|
226
|
+
|
|
227
|
+
#### HTTP Method Decorators
|
|
228
|
+
Route handlers: `@Get`, `@Post`, `@Put`, `@Delete`, `@Patch`
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
@Controller('/api/users')
|
|
232
|
+
export class UserController {
|
|
233
|
+
@Get('/')
|
|
234
|
+
getAllUsers() {
|
|
235
|
+
return { users: [] };
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
@Get('/:id')
|
|
239
|
+
getUserById(@Param('id') id: string) {
|
|
240
|
+
return { id };
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
@Post('/')
|
|
244
|
+
createUser(@Body() data: any) {
|
|
245
|
+
return { created: true };
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
#### @PostConstruct
|
|
251
|
+
Called after dependency injection.
|
|
252
|
+
|
|
253
|
+
```typescript
|
|
254
|
+
@Service()
|
|
255
|
+
export class MyService {
|
|
256
|
+
@PostConstruct()
|
|
257
|
+
init() {
|
|
258
|
+
console.log('Service initialized');
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
#### @PreDestroy
|
|
264
|
+
Called before bean destruction.
|
|
265
|
+
|
|
266
|
+
```typescript
|
|
267
|
+
@Service()
|
|
268
|
+
export class MyService {
|
|
269
|
+
@PreDestroy()
|
|
270
|
+
cleanup() {
|
|
271
|
+
console.log('Cleaning up resources');
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### Parameter Decorators
|
|
277
|
+
|
|
278
|
+
#### @Body
|
|
279
|
+
Extract request body.
|
|
280
|
+
|
|
281
|
+
```typescript
|
|
282
|
+
@Post('/')
|
|
283
|
+
createUser(@Body() userData: CreateUserDto) {
|
|
284
|
+
// userData contains request body
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
#### @Param
|
|
289
|
+
Extract route parameter.
|
|
290
|
+
|
|
291
|
+
```typescript
|
|
292
|
+
@Get('/:id')
|
|
293
|
+
getUser(@Param('id') id: string) {
|
|
294
|
+
// id from route parameter
|
|
295
|
+
}
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
#### @Query
|
|
299
|
+
Extract query parameter.
|
|
300
|
+
|
|
301
|
+
```typescript
|
|
302
|
+
@Get('/')
|
|
303
|
+
getUsers(@Query('page') page: string, @Query('limit') limit: string) {
|
|
304
|
+
// page and limit from query string
|
|
305
|
+
}
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
#### @Header
|
|
309
|
+
Extract header value.
|
|
310
|
+
|
|
311
|
+
```typescript
|
|
312
|
+
@Get('/')
|
|
313
|
+
getData(@Header('authorization') auth: string) {
|
|
314
|
+
// auth from Authorization header
|
|
315
|
+
}
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
#### @Req, @Res
|
|
319
|
+
Access raw request/response objects.
|
|
320
|
+
|
|
321
|
+
```typescript
|
|
322
|
+
@Get('/')
|
|
323
|
+
getData(@Req() req: Request, @Res() res: Response) {
|
|
324
|
+
// Full Express request/response
|
|
325
|
+
}
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
## CLI Commands
|
|
329
|
+
|
|
330
|
+
### Development
|
|
331
|
+
|
|
332
|
+
```bash
|
|
333
|
+
# Start development server (watches TypeScript files)
|
|
334
|
+
fragment serve
|
|
335
|
+
|
|
336
|
+
# Or with specific host/port
|
|
337
|
+
fragment serve --host 0.0.0.0 --port 3000
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### Build
|
|
341
|
+
|
|
342
|
+
```bash
|
|
343
|
+
# Compile TypeScript to JavaScript
|
|
344
|
+
fragment build
|
|
345
|
+
|
|
346
|
+
# Build and watch for changes
|
|
347
|
+
fragment build --watch
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
### Testing
|
|
351
|
+
|
|
352
|
+
```bash
|
|
353
|
+
# Run all tests
|
|
354
|
+
fragment test
|
|
355
|
+
|
|
356
|
+
# Run tests in watch mode
|
|
357
|
+
fragment test --watch
|
|
358
|
+
|
|
359
|
+
# Run specific test pattern
|
|
360
|
+
fragment test --pattern "**/*.spec.ts"
|
|
361
|
+
|
|
362
|
+
# Run tests in production mode (compiled)
|
|
363
|
+
fragment test --env prod
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
### Database Migrations
|
|
367
|
+
|
|
368
|
+
```bash
|
|
369
|
+
# Generate migration
|
|
370
|
+
fragment migrate:generate CreateUsers
|
|
371
|
+
|
|
372
|
+
# Run migrations
|
|
373
|
+
fragment migrate:run
|
|
374
|
+
|
|
375
|
+
# Revert last migration
|
|
376
|
+
fragment migrate:revert
|
|
377
|
+
|
|
378
|
+
# Show migration status
|
|
379
|
+
fragment migrate:show
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
### Diagnostics
|
|
383
|
+
|
|
384
|
+
```bash
|
|
385
|
+
# List all routes
|
|
386
|
+
fragment routes
|
|
387
|
+
|
|
388
|
+
# List all beans (components)
|
|
389
|
+
fragment beans
|
|
390
|
+
|
|
391
|
+
# Show as tree
|
|
392
|
+
fragment beans --tree
|
|
393
|
+
|
|
394
|
+
# Show application info
|
|
395
|
+
fragment info
|
|
396
|
+
|
|
397
|
+
# Show configuration
|
|
398
|
+
fragment config
|
|
399
|
+
|
|
400
|
+
# Show version
|
|
401
|
+
fragment version
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
### Code Generation
|
|
405
|
+
|
|
406
|
+
```bash
|
|
407
|
+
# Generate controller
|
|
408
|
+
fragment generate controller User
|
|
409
|
+
|
|
410
|
+
# Generate service
|
|
411
|
+
fragment generate service User
|
|
412
|
+
|
|
413
|
+
# Generate repository
|
|
414
|
+
fragment generate repository User
|
|
415
|
+
|
|
416
|
+
# Generate entity
|
|
417
|
+
fragment generate entity User
|
|
418
|
+
|
|
419
|
+
# Generate complete CRUD module
|
|
420
|
+
fragment generate module User
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
## Testing Guide
|
|
424
|
+
|
|
425
|
+
### Writing Tests
|
|
426
|
+
|
|
427
|
+
Create test files with `.spec.ts` extension:
|
|
428
|
+
|
|
429
|
+
```typescript
|
|
430
|
+
// user.service.spec.ts
|
|
431
|
+
import 'reflect-metadata';
|
|
432
|
+
import { UserService } from './user.service';
|
|
433
|
+
import { DIContainer } from 'fragment-ts';
|
|
434
|
+
|
|
435
|
+
describe('UserService', () => {
|
|
436
|
+
let service: UserService;
|
|
437
|
+
let container: DIContainer;
|
|
438
|
+
|
|
439
|
+
beforeEach(() => {
|
|
440
|
+
container = DIContainer.getInstance();
|
|
441
|
+
container.reset();
|
|
442
|
+
service = container.resolve(UserService);
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
it('should create user', async () => {
|
|
446
|
+
const user = await service.createUser({
|
|
447
|
+
name: 'Test',
|
|
448
|
+
email: 'test@example.com'
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
expect(user.name).toBe('Test');
|
|
452
|
+
expect(user.email).toBe('test@example.com');
|
|
453
|
+
});
|
|
454
|
+
});
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
### Test Functions
|
|
458
|
+
|
|
459
|
+
- `describe(name, fn)` - Test suite
|
|
460
|
+
- `it(name, fn)` - Test case
|
|
461
|
+
- `expect(value)` - Assertion
|
|
462
|
+
- `.toBe(expected)` - Strict equality
|
|
463
|
+
- `.toEqual(expected)` - Deep equality
|
|
464
|
+
- `.toBeTruthy()` - Truthy check
|
|
465
|
+
- `.toBeFalsy()` - Falsy check
|
|
466
|
+
- `.toThrow()` - Function throws
|
|
467
|
+
- `.toBeInstanceOf(class)` - Instance check
|
|
468
|
+
- `.toContain(value)` - Array/string contains
|
|
469
|
+
- `.toHaveProperty(prop, value?)` - Object has property
|
|
470
|
+
- `.toBeNull()` - Null check
|
|
471
|
+
- `.toBeUndefined()` - Undefined check
|
|
472
|
+
- `.toHaveLength(n)` - Length check
|
|
473
|
+
|
|
474
|
+
## Troubleshooting
|
|
475
|
+
|
|
476
|
+
### @Autowired not working
|
|
477
|
+
|
|
478
|
+
**Problem:** Properties are undefined after injection.
|
|
479
|
+
|
|
480
|
+
**Solution:**
|
|
481
|
+
1. Ensure `emitDecoratorMetadata: true` in tsconfig.json
|
|
482
|
+
2. Import `reflect-metadata` at app entry point
|
|
483
|
+
3. Make sure the dependency is registered in DI container
|
|
484
|
+
4. Check that decorators are applied in correct order
|
|
485
|
+
|
|
486
|
+
```typescript
|
|
487
|
+
import 'reflect-metadata'; // Add this at the top of main file
|
|
488
|
+
|
|
489
|
+
@Service() // Must be before class
|
|
490
|
+
export class MyService {
|
|
491
|
+
@Autowired() // Property decorator
|
|
492
|
+
private dep!: MyDependency; // Use ! for definite assignment
|
|
493
|
+
}
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
### TypeORM Repository not injected
|
|
497
|
+
|
|
498
|
+
**Problem:** Repository is undefined in @Repository classes.
|
|
499
|
+
|
|
500
|
+
**Solution:**
|
|
501
|
+
1. Make sure TypeORM is initialized before app bootstrap
|
|
502
|
+
2. Use @InjectRepository with the entity class
|
|
503
|
+
3. Entity must be decorated with @Entity
|
|
504
|
+
|
|
505
|
+
```typescript
|
|
506
|
+
@Entity()
|
|
507
|
+
export class User {
|
|
508
|
+
@PrimaryGeneratedColumn()
|
|
509
|
+
id!: number;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
@Repository()
|
|
513
|
+
export class UserRepository {
|
|
514
|
+
@InjectRepository(User) // Pass entity class
|
|
515
|
+
private repo!: Repository<User>;
|
|
516
|
+
}
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
### Tests not running
|
|
520
|
+
|
|
521
|
+
**Problem:** `fragment test` finds no tests.
|
|
522
|
+
|
|
523
|
+
**Solution:**
|
|
524
|
+
1. Test files must end with `.spec.ts`
|
|
525
|
+
2. Place tests in `src/` directory
|
|
526
|
+
3. Use correct test pattern: `--pattern "**/*.spec.ts"`
|
|
527
|
+
|
|
528
|
+
### Environment variables not loading
|
|
529
|
+
|
|
530
|
+
**Problem:** @Value decorator returns empty string.
|
|
531
|
+
|
|
532
|
+
**Solution:**
|
|
533
|
+
1. Create `.env` file in project root
|
|
534
|
+
2. Use correct syntax: `${VAR_NAME}` or `${VAR_NAME:default}`
|
|
535
|
+
3. Install dotenv: `npm install dotenv`
|
|
536
|
+
|
|
537
|
+
## Best Practices
|
|
538
|
+
|
|
539
|
+
1. **Single Responsibility** - Each service should have one clear purpose
|
|
540
|
+
2. **Dependency Injection** - Use @Autowired instead of creating instances
|
|
541
|
+
3. **Type Safety** - Always define types for method parameters and returns
|
|
542
|
+
4. **Error Handling** - Use try-catch blocks in controllers
|
|
543
|
+
5. **Testing** - Write tests for all services and repositories
|
|
544
|
+
6. **Environment Config** - Never hardcode secrets, use .env files
|
|
545
|
+
7. **Migrations** - Always use migrations, never synchronize in production
|
|
546
|
+
|
|
547
|
+
## Example Project Structure
|
|
548
|
+
|
|
549
|
+
```
|
|
550
|
+
my-app/
|
|
551
|
+
├── src/
|
|
552
|
+
│ ├── app.ts # Application entry
|
|
553
|
+
│ ├── entities/
|
|
554
|
+
│ │ └── user.entity.ts # TypeORM entities
|
|
555
|
+
│ ├── repositories/
|
|
556
|
+
│ │ └── user.repository.ts # Data access layer
|
|
557
|
+
│ ├── services/
|
|
558
|
+
│ │ ├── user.service.ts # Business logic
|
|
559
|
+
│ │ └── email.service.ts # Utilities
|
|
560
|
+
│ ├── controllers/
|
|
561
|
+
│ │ └── user.controller.ts # REST endpoints
|
|
562
|
+
│ └── __tests__/
|
|
563
|
+
│ └── user.service.spec.ts # Tests
|
|
564
|
+
├── dist/ # Compiled output
|
|
565
|
+
├── migrations/ # Database migrations
|
|
566
|
+
├── .env # Environment variables
|
|
567
|
+
├── fragment.json # Framework config
|
|
568
|
+
├── tsconfig.json # TypeScript config
|
|
569
|
+
└── package.json # Dependencies
|
|
570
|
+
```
|