From bb93245fa4b9f82b24f359fd7df7f68484080c7d Mon Sep 17 00:00:00 2001 From: SaidSoighiri94 Date: Thu, 4 Jun 2026 13:31:32 +0200 Subject: [PATCH] chore(backend): bootstrap Express + TypeScript + Prisma --- eme-backend/package.json | 36 +++++++++++++++++++++++++ eme-backend/prisma.config.ts | 12 +++++++++ eme-backend/src/app.ts | 33 +++++++++++++++++++++++ eme-backend/src/config/env.ts | 47 +++++++++++++++++++++++++++++++++ eme-backend/src/db/prisma.ts | 31 ++++++++++++++++++++++ eme-backend/src/models/enums.ts | 41 ++++++++++++++++++++++++++++ eme-backend/tsconfig.json | 17 ++++++++++++ 7 files changed, 217 insertions(+) create mode 100644 eme-backend/package.json create mode 100644 eme-backend/prisma.config.ts create mode 100644 eme-backend/src/app.ts create mode 100644 eme-backend/src/config/env.ts create mode 100644 eme-backend/src/db/prisma.ts create mode 100644 eme-backend/src/models/enums.ts create mode 100644 eme-backend/tsconfig.json diff --git a/eme-backend/package.json b/eme-backend/package.json new file mode 100644 index 0000000..0cb11f9 --- /dev/null +++ b/eme-backend/package.json @@ -0,0 +1,36 @@ +{ + "name": "eme-backend", + "version": "1.0.0", + "description": "EME — Emprunt Matériel ENSUP — API REST", + "main": "dist/app.js", + "scripts": { + "build": "tsc", + "start": "node dist/app.js", + "dev": "nodemon --exec ts-node src/app.ts", + "prisma:generate": "prisma generate", + "prisma:migrate": "prisma migrate dev", + "prisma:studio": "prisma studio" + }, + "keywords": [], + "author": "", + "license": "ISC", + "type": "commonjs", + "devDependencies": { + "@types/cors": "^2.8.19", + "@types/express": "^5.0.6", + "@types/jsonwebtoken": "^9.0.10", + "@types/node": "^25.9.1", + "nodemon": "^3.1.14", + "prisma": "^7.8.0", + "ts-node": "^10.9.2", + "typescript": "^6.0.3" + }, + "dependencies": { + "@prisma/adapter-mssql": "^7.8.0", + "@prisma/client": "^7.8.0", + "cors": "^2.8.6", + "dotenv": "^17.4.2", + "express": "^5.2.1", + "jsonwebtoken": "^9.0.3" + } +} diff --git a/eme-backend/prisma.config.ts b/eme-backend/prisma.config.ts new file mode 100644 index 0000000..921e7b4 --- /dev/null +++ b/eme-backend/prisma.config.ts @@ -0,0 +1,12 @@ +import 'dotenv/config'; +import { defineConfig, env } from 'prisma/config'; + +export default defineConfig({ + schema: 'prisma/schema.prisma', + migrations: { + path: 'prisma/migrations', + }, + datasource: { + url: env('DATABASE_URL'), + }, +}); diff --git a/eme-backend/src/app.ts b/eme-backend/src/app.ts new file mode 100644 index 0000000..2a15a70 --- /dev/null +++ b/eme-backend/src/app.ts @@ -0,0 +1,33 @@ +import express from 'express'; +import cors from 'cors'; +import { env } from './config/env'; +import { connectDatabase, disconnectDatabase } from './db/prisma'; + +const app = express(); + +// Middlewares globaux +app.use(cors()); +app.use(express.json()); + +// Route de test +app.get('/health', (_req, res) => { + res.json({ status: 'ok', app: 'EME API' }); +}); + +async function bootstrap(): Promise { + await connectDatabase(); + + const server = app.listen(env.port, () => { + console.log(`[EME API] Serveur demarre sur http://localhost:${env.port}`); + }); + + process.on('SIGINT', async () => { + await disconnectDatabase(); + server.close(() => process.exit(0)); + }); +} + +bootstrap().catch((error: unknown) => { + console.error('[EME API] Echec du demarrage', error); + process.exit(1); +}); diff --git a/eme-backend/src/config/env.ts b/eme-backend/src/config/env.ts new file mode 100644 index 0000000..bf33942 --- /dev/null +++ b/eme-backend/src/config/env.ts @@ -0,0 +1,47 @@ +import dotenv from 'dotenv'; + +dotenv.config(); + +function required(name: string): string { + const value = process.env[name]; + + if (!value) { + throw new Error(`Variable d'environnement manquante: ${name}`); + } + + return value; +} + +function numberFromEnv(name: string, defaultValue: number): number { + const value = process.env[name]; + + if (!value) { + return defaultValue; + } + + const parsed = Number(value); + + if (Number.isNaN(parsed)) { + throw new Error(`Variable d'environnement invalide: ${name}`); + } + + return parsed; +} + +export const env = { + port: numberFromEnv('PORT', 3000), + nodeEnv: process.env.NODE_ENV || 'development', + frontendUrl: required('FRONTEND_URL'), + databaseUrl: required('DATABASE_URL'), + db: { + server: required('DB_SERVER'), + port: numberFromEnv('DB_PORT', 1433), + name: required('DB_NAME'), + user: required('DB_USER'), + password: required('DB_PASSWORD'), + }, + azure: { + tenantId: required('AZURE_TENANT_ID'), + clientId: required('AZURE_CLIENT_ID'), + }, +}; diff --git a/eme-backend/src/db/prisma.ts b/eme-backend/src/db/prisma.ts new file mode 100644 index 0000000..ad4d0fa --- /dev/null +++ b/eme-backend/src/db/prisma.ts @@ -0,0 +1,31 @@ +import { PrismaClient } from '@prisma/client'; +import { PrismaMssql } from '@prisma/adapter-mssql'; +import { env } from '../config/env'; + +const adapter = new PrismaMssql({ + server: env.db.server, + port: env.db.port, + database: env.db.name, + user: env.db.user, + password: env.db.password, + options: { + encrypt: true, + trustServerCertificate: true, + }, + pool: { + max: 10, + min: 0, + idleTimeoutMillis: 30000, + }, +}); + +export const prisma = new PrismaClient({ adapter }); + +export async function connectDatabase(): Promise { + await prisma.$connect(); + console.log('[DB] Connexion SQL Server via Prisma etablie'); +} + +export async function disconnectDatabase(): Promise { + await prisma.$disconnect(); +} diff --git a/eme-backend/src/models/enums.ts b/eme-backend/src/models/enums.ts new file mode 100644 index 0000000..0525ce0 --- /dev/null +++ b/eme-backend/src/models/enums.ts @@ -0,0 +1,41 @@ +export const STATUT_MATERIEL = [ + 'DISPONIBLE', + 'EMPRUNTE', + 'NON_CONFORME', + 'DETERIORE', + 'MAINTENANCE', + 'INDISPONIBLE', +] as const; + +export type StatutMateriel = (typeof STATUT_MATERIEL)[number]; + +export const STATUT_EMPRUNT = [ + 'EN_COURS', + 'EN_RETARD', + 'CLOTURE', + 'RETOUR_NON_CONFORME', + 'ANNULE', +] as const; + +export type StatutEmprunt = (typeof STATUT_EMPRUNT)[number]; + +export const TYPE_CHECKLIST = ['DEPART', 'RETOUR'] as const; + +export type TypeChecklist = (typeof TYPE_CHECKLIST)[number]; + +export const ETAT_CHECKLIST_ELEMENT = ['PRESENT', 'ABSENT', 'DETERIORE'] as const; + +export type EtatChecklistElement = (typeof ETAT_CHECKLIST_ELEMENT)[number]; + +export const STATUT_ANOMALIE = [ + 'DETECTEE', + 'EN_COURS_TRAITEMENT', + 'RESOLUE', + 'CLOTUREE', +] as const; + +export type StatutAnomalie = (typeof STATUT_ANOMALIE)[number]; + +export const MODE_IDENTIFICATION = ['QR_CODE', 'MAIL_ENSUP'] as const; + +export type ModeIdentification = (typeof MODE_IDENTIFICATION)[number]; diff --git a/eme-backend/tsconfig.json b/eme-backend/tsconfig.json new file mode 100644 index 0000000..ac5b72a --- /dev/null +++ b/eme-backend/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "commonjs", + "rootDir": "./src", + "outDir": "./dist", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "sourceMap": true, + "types": ["node"] + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] +} \ No newline at end of file