Skip to content

Commit 44aa1c3

Browse files
authored
Merge pull request #249 from kike-alt/feat/replace-typeorm-synchronize
Feat/replace typeorm synchronize
2 parents f683178 + 1a7b1e9 commit 44aa1c3

3 files changed

Lines changed: 112 additions & 0 deletions

File tree

backend/docs/migration-workflow.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Migration Workflow Notes
2+
3+
This document outlines the expected TypeORM migration process for issue #229. The goal is to replace `synchronize: true` with an explicit, predictable migration workflow that can be run via the TypeORM CLI.
4+
5+
## 1. Generate a migration
6+
7+
1. Ensure your entity definitions are stable.
8+
2. Run `npm run migration:generate -- -n DescribeChange` to produce a timestamped migration file under `src/migrations`.
9+
3. Review the generated SQL carefully before committing.
10+
11+
## 2. Run migrations
12+
13+
Use `npm run migration:run` to apply every pending migration to the target database. This is the command to execute after a fresh `npm install` or when deploying to a new environment.
14+
15+
## 3. Revert the last migration
16+
17+
If you need to back out the most recent change, run `npm run migration:revert`. This command rolls back the latest migration that was applied.
18+
19+
## 4. Best practices
20+
21+
- Commit each migration file alongside the code changes that require it.
22+
- Never set `synchronize: true` in production—always use migrations so schema changes are tracked.
23+
- Tag the database version (optional) to align with releases if you have multiple deploy targets.
24+
- Keep any SQL manual adjustments documented in this file when automatic generation falls short.
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import {
2+
ArgumentsHost,
3+
Catch,
4+
ExceptionFilter,
5+
HttpException,
6+
HttpStatus,
7+
Logger,
8+
} from '@nestjs/common';
9+
import { Response, Request } from 'express';
10+
11+
@Catch()
12+
export class HttpExceptionFilter implements ExceptionFilter {
13+
private readonly logger = new Logger(HttpExceptionFilter.name);
14+
15+
constructor(private readonly isProduction = false) {}
16+
17+
catch(exception: unknown, host: ArgumentsHost) {
18+
const ctx = host.switchToHttp();
19+
const response = ctx.getResponse<Response>();
20+
const request = ctx.getRequest<Request>();
21+
22+
const isHttp = exception instanceof HttpException;
23+
const status = isHttp
24+
? exception.getStatus()
25+
: HttpStatus.INTERNAL_SERVER_ERROR;
26+
27+
const errorResponse = isHttp
28+
? exception.getResponse()
29+
: { message: (exception as Error)?.message }; // fallback message
30+
31+
const { message, error } = this.normalizeResponse(errorResponse, exception);
32+
33+
const payload = {
34+
statusCode: status,
35+
message,
36+
error,
37+
timestamp: new Date().toISOString(),
38+
path: request.url,
39+
};
40+
41+
this.logger.error(
42+
${status} -> ,
43+
(exception as Error)?.stack,
44+
);
45+
46+
if (!this.isProduction && exception instanceof Error) {
47+
Object.assign(payload, { stack: exception.stack });
48+
}
49+
50+
response.status(status).json(payload);
51+
}
52+
53+
private normalizeResponse(
54+
response: string | object | null | undefined,
55+
exception: unknown,
56+
) {
57+
let message = 'Internal server error';
58+
let error = HttpStatus.INTERNAL_SERVER_ERROR.toString();
59+
60+
if (typeof response === 'string') {
61+
message = response;
62+
} else if (response && typeof response === 'object') {
63+
const body = response as Record<string, any>;
64+
if (body.message) {
65+
message = Array.isArray(body.message)
66+
? body.message.join(', ')
67+
: body.message;
68+
} else if (exception instanceof Error && exception.message) {
69+
message = exception.message;
70+
}
71+
72+
if (body.error) {
73+
error = body.error;
74+
}
75+
} else if (exception instanceof Error) {
76+
message = exception.message;
77+
}
78+
79+
return { message, error };
80+
}
81+
}

backend/src/main.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { AppModule } from './app.module';
33
import { ValidationPipe } from '@nestjs/common';
44
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
55
import { ConfigService } from '@nestjs/config';
6+
import { HttpExceptionFilter } from './common/filters/http-exception.filter';
67

78
async function bootstrap() {
89
const app = await NestFactory.create(AppModule);
@@ -31,6 +32,12 @@ async function bootstrap() {
3132
}),
3233
);
3334

35+
app.useGlobalFilters(
36+
new HttpExceptionFilter(
37+
configService.get<string>('NODE_ENV') === 'production',
38+
),
39+
);
40+
3441
// Swagger documentation
3542
const config = new DocumentBuilder()
3643
.setTitle('SMALDA Authentication API')

0 commit comments

Comments
 (0)