Ölçeklenebilir Gerçek Zamanlı Bir İş Kurulu Oluşturmak: React, Node.js ve Google Kimlik Doğrulaması ile
Merhaba, bu makalede React, Node.js ve Google Kimlik Doğrulaması kullanarak ölçeklenebilir, gerçek zamanlı bir iş kurulu oluşturma sürecini adım adım ele alacağız. Bu makale, teknoloji meraklıları ve deneyimli geliştiriciler için bir rehber görevi görecektir.
Neden Gerçek Zamanlı Bir İş Kurulu?
Geleneksel iş kurullarının aksine, gerçek zamanlı bir iş kurulu, iş arayanların ve işverenlerin gerçek zamanlı olarak iletişim kurmasına olanak tanır. Bu, yeni iş ilanlarının anında yayınlanmasını, adayların başvurularını hemen göndermesini ve işverenlerin uygun adaylarla anında iletişime geçmesini sağlar. Bu özellik, hem iş arayanlar için zaman kazandırır hem de işverenler için verimlilik sağlar.
Projenin Temel Bileşenleri
Projemizde aşağıdaki temel bileşenleri kullanacağız:
- **React:** Kullanıcı arayüzünü oluşturmak için kullanacağımız bir JavaScript kitaplığı.
- **Node.js:** Sunucu tarafı geliştirme için kullanacağımız JavaScript çalışma zamanı.
- **Express.js:** Node.js için bir web uygulaması çerçevesi.
- **MongoDB:** Veri depolama için kullanacağımız bir NoSQL veritabanı.
- **Socket.IO:** Gerçek zamanlı iletişim sağlamak için kullanacağımız bir JavaScript kütüphanesi.
- **Google Kimlik Doğrulaması:** Kullanıcı kimlik doğrulaması için kullanacağımız bir hizmet.
Proje Yapısı
Proje yapımız aşağıdaki gibi olacaktır:
job-board/
├── client/
│ ├── src/
│ │ ├── components/
│ │ │ ├── JobCard.js
│ │ │ ├── JobList.js
│ │ │ ├── LoginForm.js
│ │ │ ├── SignupForm.js
│ │ │ ├── Navbar.js
│ │ │ └── Footer.js
│ │ ├── App.js
│ │ ├── services/
│ │ │ ├── auth.js
│ │ │ ├── job.js
│ │ ├── utils/
│ │ │ ├── axios.js
│ │ ├── styles/
│ │ │ ├── App.css
│ │ ├── index.js
│ ├── public/
│ │ ├── index.html
│ │ └── manifest.json
│ └── webpack.config.js
└── server/
├── index.js
├── config/
│ └── database.js
├── models/
│ ├── Job.js
│ └── User.js
├── routes/
│ ├── auth.js
│ ├── job.js
│ └── user.js
├── services/
│ ├── auth.js
│ ├── job.js
│ └── user.js
└── sockets/
└── index.js
Adım 1: Projenin Kurulması
Projenin temel yapısını oluşturmak için aşağıdaki adımları izleyeceğiz:
- Yeni bir proje dizini oluşturun:
mkdir job-board - Proje dizinine gidin:
cd job-board - İstemci tarafı projesini oluşturun:
npx create-react-app client - Sunucu tarafı projesini oluşturun:
mkdir server - Sunucu tarafı projesi için gerekli paketleri yükleyin:
npm install express mongoose socket.io cors dotenv
Adım 2: Veritabanı Kurulumu
MongoDB’yi veri depolama için kullanacağız. MongoDB’yi kurmak için aşağıdaki adımları izleyin:
- MongoDB’yi indirin ve kurun.
- MongoDB’yi başlatın:
mongod - MongoDB’ye bağlanın:
mongo - Bir veritabanı oluşturun:
use jobboard - Bir koleksiyon oluşturun:
db.jobs.insertOne({})
Adım 3: Modellerin Tanımlanması
Veritabanımızda kullanılacak modelleri tanımlayacağız. server/models dizininde Job.js ve User.js dosyaları oluşturun.
Job Model
const mongoose = require('mongoose');
const jobSchema = new mongoose.Schema({
title: { type: String, required: true },
company: { type: String, required: true },
location: { type: String, required: true },
description: { type: String, required: true },
createdAt: { type: Date, default: Date.now },
});
module.exports = mongoose.model('Job', jobSchema);
User Model
const mongoose = require('mongoose');
const userSchema = new mongoose.Schema({
name: { type: String, required: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
role: { type: String, default: 'user' },
createdAt: { type: Date, default: Date.now },
});
module.exports = mongoose.model('User', userSchema);
Adım 4: Sunucu Tarafı Kodunu Yazma
Sunucu tarafı kodunu yazmaya başlayalım. server/index.js dosyasını düzenleyeceğiz.
const express = require('express');
const mongoose = require('mongoose');
const cors = require('cors');
const dotenv = require('dotenv');
const http = require('http');
const socketIO = require('socket.io');
const authRoutes = require('./routes/auth');
const jobRoutes = require('./routes/job');
const userRoutes = require('./routes/user');
const app = express();
dotenv.config();
// Veritabanına bağlanma
mongoose.connect(process.env.DATABASE_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
})
.then(() => console.log('Veritabanına bağlanıldı.'))
.catch(err => console.error(err));
// Ortam ayarları
app.use(cors());
app.use(express.json());
// Rota tanımlamaları
app.use('/api/auth', authRoutes);
app.use('/api/jobs', jobRoutes);
app.use('/api/users', userRoutes);
// Sunucu başlatma
const server = http.createServer(app);
const io = socketIO(server, {
cors: {
origin: 'http://localhost:3000',
methods: ['GET', 'POST'],
},
});
io.on('connection', (socket) => {
console.log('Bir kullanıcı bağlandı.');
// Yeni iş ilanı eklendiğinde soket üzerinden yayın yapma
socket.on('new-job', (job) => {
io.emit('new-job', job);
});
socket.on('disconnect', () => {
console.log('Bir kullanıcı bağlantısını kesti.');
});
});
// Sunucuyu başlatma
const port = process.env.PORT || 5000;
server.listen(port, () => console.log(`Sunucu ${port} portunda çalışıyor.`));
Adım 5: Rota Tanımlamaları
Kullanıcı kimlik doğrulaması, iş ilanları ve kullanıcılarla ilgili işlemleri ele alacak rotaları tanımlayacağız. server/routes dizininde auth.js, job.js ve user.js dosyaları oluşturun.
Auth Routes
const express = require('express');
const router = express.Router();
const authController = require('../controllers/auth');
// Kayıt olma
router.post('/signup', authController.signup);
// Giriş yapma
router.post('/login', authController.login);
module.exports = router;
Job Routes
const express = require('express');
const router = express.Router();
const jobController = require('../controllers/job');
// Tüm iş ilanlarını listeleme
router.get('/', jobController.getJobs);
// Yeni iş ilanı ekleme
router.post('/', jobController.createJob);
// Belirli bir iş ilanını alma
router.get('/:id', jobController.getJob);
// İş ilanını güncelleme
router.put('/:id', jobController.updateJob);
// İş ilanını silme
router.delete('/:id', jobController.deleteJob);
module.exports = router;
User Routes
const express = require('express');
const router = express.Router();
const userController = require('../controllers/user');
// Tüm kullanıcıları listeleme
router.get('/', userController.getUsers);
// Belirli bir kullanıcıyı alma
router.get('/:id', userController.getUser);
// Kullanıcı bilgilerini güncelleme
router.put('/:id', userController.updateUser);
// Kullanıcıyı silme
router.delete('/:id', userController.deleteUser);
module.exports = router;
Adım 6: Denetleyicilerin Tanımlanması
Rotalar için gerekli iş mantığını içeren denetleyicileri tanımlayacağız. server/controllers dizininde auth.js, job.js ve user.js dosyaları oluşturun.
Auth Controller
const User = require('../models/User');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
// Kayıt olma
exports.signup = async (req, res) => {
try {
const { name, email, password } = req.body;
// Kullanıcı adı ve e-posta adresi zaten mevcut mu kontrol et
const existingUser = await User.findOne({ email });
if (existingUser) {
return res.status(400).json({ message: 'Kullanıcı adı veya e-posta adresi zaten mevcut.' });
}
// Şifreyi hashleyin
const hashedPassword = await bcrypt.hash(password, 10);
// Yeni kullanıcı kaydı oluşturun
const newUser = new User({ name, email, password: hashedPassword });
await newUser.save();
// JWT oluşturun
const token = jwt.sign({ userId: newUser._id }, process.env.JWT_SECRET);
res.status(201).json({ token, userId: newUser._id });
} catch (err) {
console.error(err);
res.status(500).json({ message: 'Bir hata oluştu.' });
}
};
// Giriş yapma
exports.login = async (req, res) => {
try {
const { email, password } = req.body;
// Kullanıcıyı bulun
const user = await User.findOne({ email });
if (!user) {
return res.status(401).json({ message: 'Geçersiz e-posta adresi veya şifre.' });
}
// Şifreyi doğrulayın
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) {
return res.status(401).json({ message: 'Geçersiz e-posta adresi veya şifre.' });
}
// JWT oluşturun
const token = jwt.sign({ userId: user._id }, process.env.JWT_SECRET);
res.status(200).json({ token, userId: user._id });
} catch (err) {
console.error(err);
res.status(500).json({ message: 'Bir hata oluştu.' });
}
};
Job Controller
const Job = require('../models/Job');
// Tüm iş ilanlarını listeleme
exports.getJobs = async (req, res) => {
try {
const jobs = await Job.find().sort({ createdAt: -1 });
res.status(200).json(jobs);
} catch (err) {
console.error(err);
res.status(500).json({ message: 'Bir hata oluştu.' });
}
};
// Yeni iş ilanı ekleme
exports.createJob = async (req, res) => {
try {
const { title, company, location, description } = req.body;
// Yeni iş ilanı oluşturun
const newJob = new Job({ title, company, location, description });
await newJob.save();
// Yeni iş ilanını soket üzerinden yayınlayın
io.emit('new-job', newJob);
res.status(201).json(newJob);
} catch (err) {
console.error(err);
res.status(500).json({ message: 'Bir hata oluştu.' });
}
};
// Belirli bir iş ilanını alma
exports.getJob = async (req, res) => {
try {
const job = await Job.findById(req.params.id);
if (!job) {
return res.status(404).json({ message: 'İş ilanı bulunamadı.' });
}
res.status(200).json(job);
} catch (err) {
console.error(err);
res.status(500).json({ message: 'Bir hata oluştu.' });
}
};
// İş ilanını güncelleme
exports.updateJob = async (req, res) => {
try {
const { title, company, location, description } = req.body;
const updatedJob = await Job.findByIdAndUpdate(
req.params.id,
{ title, company, location, description },
{ new: true },
);
if (!updatedJob) {
return res.status(404).json({ message: 'İş ilanı bulunamadı.' });
}
res.status(200).json(updatedJob);
} catch (err) {
console.error(err);
res.status(500).json({ message: 'Bir hata oluştu.' });
}
};
// İş ilanını silme
exports.deleteJob = async (req, res) => {
try {
const deletedJob = await Job.findByIdAndDelete(req.params.id);
if (!deletedJob) {
return res.status(404).json({ message: 'İş ilanı bulunamadı.' });
}
res.status(200).json({ message: 'İş ilanı silindi.' });
} catch (err) {
console.error(err);
res.status(500).json({ message: 'Bir hata oluştu.' });
}
};
User Controller
const User = require('../models/User');
// Tüm kullanıcıları listeleme
exports.getUsers = async (req, res) => {
try {
const users = await User.find();
res.status(200).json(users);
} catch (err) {
console.error(err);
res.status(500).json({ message: 'Bir hata oluştu.' });
}
};
// Belirli bir kullanıcıyı alma
exports.getUser = async (req, res) => {
try {
const user = await User.findById(req.params.id);
if (!user) {
return res.status(404).json({ message: 'Kullanıcı bulunamadı.' });
}
res.status(200).json(user);
} catch (err) {
console.error(err);
res.status(500).json({ message: 'Bir hata oluştu.' });
}
};
// Kullanıcı bilgilerini güncelleme
exports.updateUser = async (req, res) => {
try {
const { name, email, password } = req.body;
const updatedUser = await User.findByIdAndUpdate(
req.params.id,
{ name, email, password },
{ new: true },
);
if (!updatedUser) {
return res.status(404).json({ message: 'Kullanıcı bulunamadı.' });
}
res.status(200).json(updatedUser);
} catch (err) {
console.error(err);
res.status(500).json({ message: 'Bir hata oluştu.' });
}
};
// Kullanıcıyı silme
exports.deleteUser = async (req, res) => {
try {
const deletedUser = await User.findByIdAndDelete(req.params.id);
if (!deletedUser) {
return res.status(404).json({ message: 'Kullanıcı bulunamadı.' });
}
res.status(200).json({ message: 'Kullanıcı silindi.' });
} catch (err) {
console.error(err);
res.status(500).json({ message: 'Bir hata oluştu.' });
}
};
Adım 7: İstemci Tarafı Kodunu Yazma
İstemci tarafı kodunu yazmaya başlayalım. client/src dizininde App.js dosyasını düzenleyeceğiz.
import React, { useState, useEffect } from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import JobList from './components/JobList';
import JobDetails from './components/JobDetails';
import LoginForm from './components/LoginForm';
import SignupForm from './components/SignupForm';
import Navbar from './components/Navbar';
import Footer from './components/Footer';
import AuthContext from './context/AuthContext';
import axios from './utils/axios';
function App() {
const [authTokens, setAuthTokens] = useState(null);
const [user, setUser] = useState(null);
const setTokens = (data) => {
localStorage.setItem('tokens', JSON.stringify(data));
setAuthTokens(data);
};
const getUser = async () => {
const response = await axios.get('/api/users/me', {
headers: {
Authorization: `Bearer ${authTokens.access_token}`,
},
});
setUser(response.data);
};
useEffect(() => {
const tokens = JSON.parse(localStorage.getItem('tokens'));
if (tokens) {
setTokens(tokens);
getUser();
}
}, []);
const logout = () => {
localStorage.removeItem('tokens');
setAuthTokens(null);
setUser(null);
};
return (
} />
} />
} />
} />
);
}
export default App;
Adım 8: Google Kimlik Doğrulaması
Google Kimlik Doğrulaması’nı kullanarak kullanıcıların giriş yapmasını ve kaydolmasını sağlayacağız.
- Google Cloud Console’da bir proje oluşturun.
- Proje için OAuth 2.0 kimlik bilgisi oluşturun.
- Uygulama türü: Web uygulaması
- Yetkilendirme URL’si:
http://localhost:3000/api/auth/google/callback - Onaylanmış köken URL’si:
http://localhost:3000 - Gelişmiş ayarlar:
- JWT yayınlayıcısı: Google’ın yayınlayıcısını seçin.
- JWT alıcısı:
YOUR_CLIENT_ID.apps.googleusercontent.com
- Google Kimlik Doğrulaması kimlik bilgilerini
server/config/database.jsdosyasında saklayın. - Sunucu tarafında Google Kimlik Doğrulaması için rotaları ayarlayın.
- İstemci tarafında Google Kimlik Doğrulaması için kütüphaneyi kullanarak Google’a giriş yapma seçeneği ekleyin.
Adım 9: Gerçek Zamanlı İşlevselliği Uygulama
Socket.IO kullanarak gerçek zamanlı işlevselliği uygulayacağız. server/sockets/index.js dosyasını düzenleyerek yeni iş ilanları eklendiğinde gerçek zamanlı güncellemeleri ileteceğiz.
Adım 10: Ölçeklenebilirlik
Projenin ölçeklenebilirliğini artırmak için aşağıdaki ipuçlarını kullanabilirsiniz:
- **Veritabanı ölçekleme:** MongoDB’de sharding ve replica setleri kullanarak veritabanını ölçekleyebilirsiniz.
- **Sunucu tarafı ölçekleme:** Sunucuyu Node.js cluster modunu veya bir yük dengeleyici kullanarak ölçekleyebilirsiniz.
- **İstemci tarafı performans optimizasyonu:** İstemci tarafı performansını artırmak için React’in özelliklerini kullanın.
- **İstemci tarafı önbellekleme:** İstemci tarafında önbellekleme kullanarak sunucuya yapılan istek sayısını azaltabilirsiniz.
Sonuç
Bu makalede, React, Node.js ve Google Kimlik Doğrulaması kullanarak ölçeklenebilir, gerçek zamanlı bir iş kurulu oluşturma sürecini adım adım ele aldık. Projede kullanılan teknolojileri ve tasarım desenlerini derinlemesine inceleyerek projenin yapı taşlarını oluşturduk.
Bu projede, gerçek zamanlı işlevsellik, Google Kimlik Doğrulaması ve ölçeklenebilirlik gibi önemli konulara değinildi. Bu makaleyi bir başlangıç noktası olarak kabul ederek projenizi kendi ihtiyaçlarınıza göre özelleştirebilirsiniz. Daha fazla bilgi ve örnek için fatihsoysal.com sitesini ziyaret edebilirsiniz.
Umarım bu makale, kendi gerçek zamanlı iş kurulunuzu oluşturmanıza yardımcı olur! Başarılar!