refactor(api): version routes and externalize client base url

- serve REST endpoints under /api/v1 with root exceptions for health and mcp

- move swagger UI to /docs and allow direct frontend calls via CORS

- remove Vite proxy/hash routing and rely on env-driven VITE_API_URL
This commit is contained in:
2026-04-10 22:53:32 +03:00
parent ccce3381c1
commit 11db983ea6
7 changed files with 38 additions and 19 deletions
+1 -1
View File
@@ -23,7 +23,7 @@ export class AppConfig {
KEYS_DIR: string = "keys";
@IsString()
DB_PATH: string = "data/sessions.db";
DB_PATH: string = "data/liqa.db";
@IsInt()
@Min(1)
+7
View File
@@ -4,6 +4,13 @@ import { ApiOperation, ApiResponse, ApiTags } from "@nestjs/swagger";
@ApiTags("health")
@Controller()
export class HealthController {
@Get("health")
@ApiOperation({ summary: "Health check" })
@ApiResponse({ status: 200, description: "Service is healthy" })
health(): { status: string } {
return { status: "ok" };
}
@Get("healthz")
@ApiOperation({ summary: "Health check" })
@ApiResponse({ status: 200, description: "Service is healthy" })
+21 -3
View File
@@ -1,7 +1,7 @@
import { NestFactory } from "@nestjs/core";
import { ConfigService } from "@nestjs/config";
import { AppConfig } from "./config/app.config";
import { ValidationPipe } from "@nestjs/common";
import { RequestMethod, ValidationPipe } from "@nestjs/common";
import { TraceLogger } from "./common/trace-logger";
import { DocumentBuilder, SwaggerModule } from "@nestjs/swagger";
import { AppModule } from "./app.module";
@@ -11,11 +11,20 @@ import { LoggingInterceptor } from "./interceptors/logging.interceptor";
import { name as pkgName, version as pkgVersion } from "../package.json";
async function bootstrap() {
const API_PREFIX = "api/v1";
const logger = new TraceLogger("Bootstrap");
const app = await NestFactory.create(AppModule, {
logger: new TraceLogger("Bootstrap", { timestamp: true }),
});
app.setGlobalPrefix(API_PREFIX, {
exclude: [
{ path: "health", method: RequestMethod.ALL },
{ path: "healthz", method: RequestMethod.ALL },
{ path: "mcp", method: RequestMethod.ALL },
],
});
app.useGlobalPipes(new ValidationPipe({ transform: true }));
app.useGlobalFilters(new HttpExceptionFilter());
app.useGlobalInterceptors(new TraceInterceptor(), new LoggingInterceptor());
@@ -24,6 +33,15 @@ async function bootstrap() {
const port = config.get("PORT");
const nodeEnv = config.get("NODE_ENV");
app.enableCors({
origin: [
"http://localhost:5173",
"http://127.0.0.1:5173",
],
methods: ["GET", "HEAD", "PUT", "PATCH", "POST", "DELETE", "OPTIONS"],
credentials: true,
});
const swaggerConfig = new DocumentBuilder()
.setTitle(pkgName)
.setDescription(`${pkgName} API`)
@@ -31,14 +49,14 @@ async function bootstrap() {
.build();
const document = SwaggerModule.createDocument(app, swaggerConfig);
SwaggerModule.setup("api", app, document);
SwaggerModule.setup("docs", app, document);
await app.listen(port);
logger.log(
`Application "${pkgName}" v${pkgVersion} running on port ${port} [${nodeEnv}]`,
);
logger.log(`Swagger UI available at http://localhost:${port}/api`);
logger.log(`Swagger UI available at http://localhost:${port}/docs`);
logger.log(`MCP endpoint available at http://localhost:${port}/mcp`);
}