first commit

This commit is contained in:
2025-11-26 18:57:18 +03:00
commit 16c21a4e49
41 changed files with 1075 additions and 0 deletions

4
backend/.dockerignore Normal file
View File

@@ -0,0 +1,4 @@
node_modules
npm-debug.log
dist
.env

6
backend/.env.example Normal file
View 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
View 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
View 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
View 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
View 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();

View 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" });
}
};

View 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
View 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"]
}