first commit
This commit is contained in:
4
backend/.dockerignore
Normal file
4
backend/.dockerignore
Normal file
@@ -0,0 +1,4 @@
|
||||
node_modules
|
||||
npm-debug.log
|
||||
dist
|
||||
.env
|
||||
6
backend/.env.example
Normal file
6
backend/.env.example
Normal file
@@ -0,0 +1,6 @@
|
||||
PORT=4000
|
||||
MONGO_URI=mongodb://mongo:27017/wisecoltci
|
||||
ADMIN_USERNAME=admin
|
||||
ADMIN_PASSWORD=supersecret
|
||||
JWT_SECRET=change-me
|
||||
CLIENT_ORIGIN=http://localhost:5173
|
||||
12
backend/Dockerfile
Normal file
12
backend/Dockerfile
Normal file
@@ -0,0 +1,12 @@
|
||||
FROM node:20-alpine
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY package*.json .
|
||||
RUN npm install
|
||||
|
||||
COPY tsconfig.json .
|
||||
COPY src ./src
|
||||
|
||||
EXPOSE 4000
|
||||
CMD ["npm", "run", "dev"]
|
||||
28
backend/package.json
Normal file
28
backend/package.json
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "backend",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "tsx watch src/index.ts",
|
||||
"build": "tsc -p tsconfig.json",
|
||||
"start": "node dist/index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^16.3.1",
|
||||
"express": "^4.18.2",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"mongoose": "^7.6.3",
|
||||
"socket.io": "^4.7.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/cors": "^2.8.17",
|
||||
"@types/express": "^4.17.21",
|
||||
"@types/jsonwebtoken": "^9.0.5",
|
||||
"@types/node": "^20.9.0",
|
||||
"ts-node": "^10.9.2",
|
||||
"tsx": "^4.7.1",
|
||||
"typescript": "^5.2.2"
|
||||
}
|
||||
}
|
||||
16
backend/src/config/env.ts
Normal file
16
backend/src/config/env.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import dotenv from "dotenv";
|
||||
|
||||
dotenv.config();
|
||||
|
||||
export const config = {
|
||||
port: parseInt(process.env.PORT || "4000", 10),
|
||||
mongoUri: process.env.MONGO_URI || "mongodb://mongo:27017/wisecoltci",
|
||||
adminUsername: process.env.ADMIN_USERNAME || "admin",
|
||||
adminPassword: process.env.ADMIN_PASSWORD || "password",
|
||||
jwtSecret: process.env.JWT_SECRET || "changeme",
|
||||
clientOrigin: process.env.CLIENT_ORIGIN || "http://localhost:5173"
|
||||
};
|
||||
|
||||
if (!config.jwtSecret) {
|
||||
throw new Error("JWT_SECRET is required");
|
||||
}
|
||||
70
backend/src/index.ts
Normal file
70
backend/src/index.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import http from "http";
|
||||
import express from "express";
|
||||
import cors from "cors";
|
||||
import mongoose from "mongoose";
|
||||
import { Server } from "socket.io";
|
||||
import authRoutes from "./routes/auth.js";
|
||||
import { config } from "./config/env.js";
|
||||
import jwt from "jsonwebtoken";
|
||||
|
||||
const app = express();
|
||||
|
||||
app.use(
|
||||
cors({
|
||||
origin: config.clientOrigin,
|
||||
credentials: true
|
||||
})
|
||||
);
|
||||
app.use(express.json());
|
||||
|
||||
app.get("/health", (_req, res) => {
|
||||
res.json({ status: "ok" });
|
||||
});
|
||||
|
||||
app.use("/auth", authRoutes);
|
||||
|
||||
const server = http.createServer(app);
|
||||
|
||||
const io = new Server(server, {
|
||||
cors: {
|
||||
origin: config.clientOrigin,
|
||||
methods: ["GET", "POST"]
|
||||
}
|
||||
});
|
||||
|
||||
io.use((socket, next) => {
|
||||
const token = socket.handshake.auth?.token as string | undefined;
|
||||
if (!token) {
|
||||
return next(new Error("Yetkisiz"));
|
||||
}
|
||||
try {
|
||||
jwt.verify(token, config.jwtSecret);
|
||||
next();
|
||||
} catch (err) {
|
||||
next(new Error("Geçersiz token"));
|
||||
}
|
||||
});
|
||||
|
||||
io.on("connection", (socket) => {
|
||||
socket.emit("hello", "Socket bağlantısı kuruldu");
|
||||
|
||||
socket.on("ping", () => {
|
||||
socket.emit("pong", "pong");
|
||||
});
|
||||
});
|
||||
|
||||
async function start() {
|
||||
try {
|
||||
await mongoose.connect(config.mongoUri);
|
||||
console.log("MongoDB'ye bağlanıldı");
|
||||
|
||||
server.listen(config.port, () => {
|
||||
console.log(`Sunucu ${config.port} portunda çalışıyor`);
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("Başlatma hatası", err);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
start();
|
||||
23
backend/src/middleware/authMiddleware.ts
Normal file
23
backend/src/middleware/authMiddleware.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { Request, Response, NextFunction } from "express";
|
||||
import jwt from "jsonwebtoken";
|
||||
import { config } from "../config/env.js";
|
||||
|
||||
export interface AuthRequest extends Request {
|
||||
user?: { username: string };
|
||||
}
|
||||
|
||||
export const authMiddleware = (req: AuthRequest, res: Response, next: NextFunction) => {
|
||||
const authHeader = req.headers.authorization;
|
||||
if (!authHeader || !authHeader.startsWith("Bearer ")) {
|
||||
return res.status(401).json({ message: "Yetkisiz" });
|
||||
}
|
||||
|
||||
const token = authHeader.split(" ")[1];
|
||||
try {
|
||||
const decoded = jwt.verify(token, config.jwtSecret) as { username: string };
|
||||
req.user = { username: decoded.username };
|
||||
next();
|
||||
} catch (err) {
|
||||
return res.status(401).json({ message: "Geçersiz token" });
|
||||
}
|
||||
};
|
||||
30
backend/src/routes/auth.ts
Normal file
30
backend/src/routes/auth.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { Router } from "express";
|
||||
import jwt from "jsonwebtoken";
|
||||
import { authMiddleware, AuthRequest } from "../middleware/authMiddleware.js";
|
||||
import { config } from "../config/env.js";
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.post("/login", (req, res) => {
|
||||
const { username, password } = req.body as { username?: string; password?: string };
|
||||
|
||||
if (!username || !password) {
|
||||
return res.status(400).json({ message: "Kullanıcı adı ve şifre gerekli" });
|
||||
}
|
||||
|
||||
if (username !== config.adminUsername || password !== config.adminPassword) {
|
||||
return res.status(401).json({ message: "Geçersiz kimlik bilgileri" });
|
||||
}
|
||||
|
||||
const token = jwt.sign({ username }, config.jwtSecret, { expiresIn: "1h" });
|
||||
return res.json({ token, username });
|
||||
});
|
||||
|
||||
router.get("/me", authMiddleware, (req: AuthRequest, res) => {
|
||||
if (!req.user) {
|
||||
return res.status(401).json({ message: "Yetkisiz" });
|
||||
}
|
||||
return res.json({ username: req.user.username });
|
||||
});
|
||||
|
||||
export default router;
|
||||
17
backend/tsconfig.json
Normal file
17
backend/tsconfig.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"outDir": "dist",
|
||||
"rootDir": "src",
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"resolveJsonModule": true,
|
||||
"types": ["node"]
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
||||
Reference in New Issue
Block a user