Task

clicktasks/ ├── client/ # Frontend (HTML/CSS/JS) ├── server/ # Backend Node.js │ ├── config/ # Configurações do banco e JWT │ ├── controllers/ # Lógica de negócios │ ├── middlewares/ # Autenticação e validações │ ├── models/ # Modelos do banco de dados │ ├── routes/ # Rotas da API │ ├── services/ # Serviços (email, OAuth, etc.) │ └── server.js # Ponto de entrada ├── .env # Variáveis de ambiente └── package.json # Dependências do Node.js require('dotenv').config(); const express = require('express'); const cors = require('cors'); const helmet = require('helmet'); const rateLimit = require('express-rate-limit'); const { Sequelize } = require('sequelize'); const authRoutes = require('./routes/auth'); const profileRoutes = require('./routes/profiles'); const app = express(); // Middlewares de segurança app.use(helmet()); app.use(cors({ origin: process.env.CLIENT_URL })); app.use(express.json()); // Limitar requisições (prevenção de brute force) const limiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15 minutos max: 100 // limite por IP }); app.use(limiter); // Conexão com MySQL const sequelize = new Sequelize( process.env.DB_NAME, process.env.DB_USER, process.env.DB_PASSWORD, { host: process.env.DB_HOST, dialect: 'mysql', logging: false } ); // Testar conexão com o banco sequelize.authenticate() .then(() => console.log('✅ Conectado ao MySQL')) .catch(err => console.error('❌ Erro na conexão:', err)); // Rotas app.use('/api/auth', authRoutes); app.use('/api/profiles', profileRoutes); // Iniciar servidor const PORT = process.env.PORT || 5000; app.listen(PORT, () => { console.log(`🚀 Servidor rodando em http://localhost:${PORT}`); }); const { DataTypes } = require('sequelize'); const sequelize = require('../config/database'); const bcrypt = require('bcryptjs'); const User = sequelize.define('User', { id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true }, name: { type: DataTypes.STRING, allowNull: false }, email: { type: DataTypes.STRING, unique: true, allowNull: false, validate: { isEmail: true } }, password: { type: DataTypes.STRING, allowNull: false, set(value) { // Hash automático da senha const salt = bcrypt.genSaltSync(10); this.setDataValue('password', bcrypt.hashSync(value, salt)); } }, userType: { type: DataTypes.ENUM('profissional', 'empresa'), allowNull: false }, isVerified: { type: DataTypes.BOOLEAN, defaultValue: false } }, { timestamps: true, paranoid: true // Soft delete }); module.exports = User; const jwt = require('jsonwebtoken'); const { jwtSecret, jwtExpiresIn } = require('./config'); const generateToken = (userId) => { return jwt.sign({ id: userId }, jwtSecret, { expiresIn: jwtExpiresIn }); }; const verifyToken = (token) => { try { return jwt.verify(token, jwtSecret); } catch (err) { return null; } }; module.exports = { generateToken, verifyToken }; const { User } = require('../models'); const { generateToken } = require('../config/jwt'); const { sendVerificationEmail } = require('../services/emailService'); const { verifyRecaptcha } = require('../services/recaptchaService'); exports.register = async (req, res) => { try { // Verificar reCAPTCHA const recaptchaValid = await verifyRecaptcha(req.body.recaptchaToken); if (!recaptchaValid) { return res.status(400).json({ error: 'Falha na verificação reCAPTCHA' }); } const { name, email, password, userType } = req.body; // Criar usuário const user = await User.create({ name, email, password, userType }); // Enviar e-mail de verificação await sendVerificationEmail(user); // Gerar token JWT const token = generateToken(user.id); res.status(201).json({ token, user: { id: user.id, name: user.name, email: user.email } }); } catch (error) { res.status(400).json({ error: error.message }); } }; exports.login = async (req, res) => { try { const { email, password } = req.body; const user = await User.findOne({ where: { email } }); if (!user || !bcrypt.compareSync(password, user.password)) { return res.status(401).json({ error: 'Credenciais inválidas' }); } const token = generateToken(user.id); res.json({ token, user: { id: user.id, name: user.name, email: user.email } }); } catch (error) { res.status(400).json({ error: error.message }); } }; // Login Social (OAuth 2.0) exports.socialAuth = async (req, res) => { // Implementação para Google/LinkedIn OAuth }; const { verifyToken } = require('../config/jwt'); exports.authenticate = async (req, res, next) => { const token = req.header('Authorization')?.replace('Bearer ', ''); if (!token) { return res.status(401).json({ error: 'Acesso não autorizado' }); } const decoded = verifyToken(token); if (!decoded) { return res.status(401).json({ error: 'Token inválido' }); } req.userId = decoded.id; next(); }; const axios = require('axios'); exports.verifyRecaptcha = async (token) => { try { const response = await axios.post( 'https://www.google.com/recaptcha/api/siteverify', `secret=${process.env.RECAPTCHA_SECRET_KEY}&response=${token}` ); return response.data.success && response.data.score >= 0.5; } catch (error) { console.error('Erro na verificação reCAPTCHA:', error); return false; } };
CREATE DATABASE clicktasks_db; CREATE TABLE Users ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100) NOT NULL, email VARCHAR(100) UNIQUE NOT NULL, password VARCHAR(255) NOT NULL, userType ENUM('profissional', 'empresa') NOT NULL, isVerified BOOLEAN DEFAULT false, createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, deletedAt TIMESTAMP NULL ); # Banco de Dados DB_HOST=localhost DB_NAME=clicktasks_db DB_USER=root DB_PASSWORD=senha_segura # Autenticação JWT_SECRET=super_secret_key JWT_EXPIRES_IN=7d # reCAPTCHA RECAPTCHA_SITE_KEY=sua_chave_site RECAPTCHA_SECRET_KEY=sua_chave_secreta # OAuth (Google) GOOGLE_CLIENT_ID=seu_client_id GOOGLE_CLIENT_SECRET=seu_client_secret # SMTP (E-mails) SMTP_HOST=smtp.example.com SMTP_PORT=587 SMTP_USER=seu_email@example.com SMTP_PASS=sua_senha bash cd server npm install express sequelize mysql2 bcryptjs jsonwebtoken axios helmet cors dotenv node server.js POST /api/auth/register POST /api/auth/login GET /api/profiles

Comentários

Postagens mais visitadas