🌊 TeamFlow — Modern Trello alternative with email integration

- Full-stack: React 18 + Express + SQLite
- Drag-and-drop kanban boards with @hello-pangea/dnd
- Google App Password email integration (SMTP + IMAP)
- Inbound email: create cards by sending emails
- Reply-to-card: email replies become comments
- Admin/user management with role-based access
- Setup wizard: email config → admin creation
- Checklists, time tracking, priorities, labels, due dates
- Real-time notifications with activity feed
- Beautiful HTML email templates
This commit is contained in:
admin
2026-04-03 15:11:27 +00:00
Unverified
commit 460f83aef8
40 changed files with 8512 additions and 0 deletions

36
server/routes/auth.js Normal file
View File

@@ -0,0 +1,36 @@
import { Router } from 'express';
import bcrypt from 'bcryptjs';
import db from '../db.js';
import { generateToken, authMiddleware } from '../middleware/auth.js';
const router = Router();
router.post('/login', (req, res) => {
const { email, password } = req.body;
if (!email || !password) return res.status(400).json({ error: 'Email and password required' });
const user = db.prepare('SELECT * FROM users WHERE email = ?').get(email);
if (!user || !user.is_active) return res.status(401).json({ error: 'Invalid credentials' });
if (!bcrypt.compareSync(password, user.password)) return res.status(401).json({ error: 'Invalid credentials' });
const token = generateToken(user);
res.json({ user: { id: user.id, email: user.email, name: user.name, avatar_color: user.avatar_color, role: user.role }, token });
});
router.get('/me', authMiddleware, (req, res) => {
res.json(req.user);
});
router.put('/me', authMiddleware, async (req, res) => {
const { name, avatar_color, current_password, new_password } = req.body;
if (name) db.prepare('UPDATE users SET name = ? WHERE id = ?').run(name, req.user.id);
if (avatar_color) db.prepare('UPDATE users SET avatar_color = ? WHERE id = ?').run(avatar_color, req.user.id);
if (new_password) {
const user = db.prepare('SELECT password FROM users WHERE id = ?').get(req.user.id);
if (!bcrypt.compareSync(current_password, user.password)) return res.status(400).json({ error: 'Current password incorrect' });
const hash = await bcrypt.hash(new_password, 12);
db.prepare('UPDATE users SET password = ? WHERE id = ?').run(hash, req.user.id);
}
const updated = db.prepare('SELECT id, email, name, avatar_color, role FROM users WHERE id = ?').get(req.user.id);
res.json(updated);
});
export default router;