import {join} from "node:path";
import {Configuration} from "@tsed/di";
import {application} from "@tsed/platform-http";
import "@tsed/platform-log-request"; // remove this import if you don't want log request
import "@tsed/platform-express"; // /!\ keep this import
import "@tsed/ajv";
import "@tsed/swagger";
import "@tsed/scalar";
import {config} from "./config/index.js";
import * as rest from "./controllers/rest/index.js";
import * as pages from "./controllers/pages/index.js";
import {testConnection, closePool} from "./config/database.js";
import {$log} from "@tsed/logger";
@Configuration({
...config,
acceptMimes: ["application/json"],
httpPort: process.env.PORT || 8083,
httpsPort: false, // CHANGE
mount: {
"/rest": [
...Object.values(rest)
],
"/": [
...Object.values(pages)
]
},
swagger: [
{
path: "/doc",
specVersion: "3.0.1",
spec: {
info: {
title: "Candivista API",
version: process.env.APP_VERSION || "1.0.0",
description:
"REST API for Candivista. Authentication via JWT Bearer tokens.\n\n" +
"Includes endpoints for auth, users, jobs, tokens, AI-powered interviews (OpenRouter/Ollama), payment processing, and admin reporting.\n\n" +
"AI Features:\n" +
"- OpenRouter integration for cloud-based AI interviews\n" +
"- Ollama support for local AI processing\n" +
"- Test mode for admin interview testing\n" +
"- Mandatory question support before AI interviews\n\n" +
"Payment Features:\n" +
"- Stripe integration for secure payments\n" +
"- Support for credit cards, iDEAL, and bank transfers\n" +
"- Dynamic token pricing with package discounts\n" +
"- Custom token quantity purchases\n" +
"- Webhook-based payment confirmation",
contact: {
name: "Candivista Team",
url: "https://candivista.com",
email: "support@candivista.com"
},
license: { name: "Proprietary" }
},
servers: [
{ url: "http://localhost:8083", description: "Local" }
],
tags: [
{ name: "Auth", description: "Authentication and session management" },
{ name: "Users", description: "User profile and token summary" },
{ name: "Jobs", description: "Job posting and interview token operations" },
{ name: "Admin", description: "Administrative statistics and management" },
{ name: "AI", description: "AI-powered interview operations with OpenRouter and Ollama support" },
{ name: "Payments", description: "Stripe payment processing for token purchases" },
{ name: "Webhooks", description: "Stripe webhook handlers for payment events" }
],
components: {
securitySchemes: {
bearerAuth: { type: "http", scheme: "bearer", bearerFormat: "JWT" }
}
},
security: [{ bearerAuth: [] }]
}
}
],
scalar: [
{
path: "/scalar/doc",
specVersion: "3.0.1"
}
],
middlewares: [
"cors",
"cookie-parser",
"compression",
"method-override",
"json-parser",
{ use: "urlencoded-parser", options: { extended: true }}
],
views: {
root: join(process.cwd(), "views"),
extensions: {
ejs: "ejs"
}
}
})
export class Server {
protected app = application();
async $onInit() {
// Test database connection on startup
const isConnected = await testConnection();
if (!isConnected) {
$log.error("Failed to connect to database. Server will continue but database operations may fail.");
}
}
async $onDestroy() {
// Close database pool on shutdown
await closePool();
}
}