AgendaPro v1.0 - multi-tenant SaaS, mobile calendar, public booking
Multi-tenant scheduling SaaS (AgendaPro-equivalent): - Backend: Node + Express + node:sqlite, multi-tenant (admin/owner/employee), versioned migrations, 4 templates (estetica-spa, barberia, clinica, blank). - Frontend: React 18 + TS + Vite + Tailwind, FullCalendar drag-and-drop, Recharts dashboard, mobile-first (day/list views on mobile). - Features: calendar+services+employees+clients+tickets, dashboard with best employee/service, top tickets, top/frequent clients, commissions, cancellation policy + no-show tracking, public online booking (/b/:slug), cash register (cierre de caja), reminders/notifications center. - Verification: 65/65 e2e API, 58/58 visual (0 overflow, 0 console errors), typecheck clean, vite build OK.
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
import { Router } from "express";
|
||||
import { db } from "../db.ts";
|
||||
import { authRequired, type AuthedRequest } from "../lib/auth.ts";
|
||||
|
||||
export const authRouter = Router();
|
||||
|
||||
authRouter.post("/login", (req, res) => {
|
||||
const { email, password } = req.body ?? {};
|
||||
if (!email || !password) return res.status(400).json({ error: "Faltan credenciales" });
|
||||
const user = db
|
||||
.prepare(`SELECT id, business_id, email, name, role, employee_id, avatar_color, password FROM users WHERE email = ?`)
|
||||
.get(String(email).toLowerCase().trim()) as any;
|
||||
if (!user || user.password !== password) {
|
||||
return res.status(401).json({ error: "Correo o contraseña incorrectos" });
|
||||
}
|
||||
const { password: _pw, ...safe } = user;
|
||||
res.json({ token: String(user.id), user: safe });
|
||||
});
|
||||
|
||||
authRouter.get("/me", authRequired, (req: AuthedRequest, res) => {
|
||||
res.json({ user: req.user });
|
||||
});
|
||||
|
||||
authRouter.get("/demo-users", (_req, res) => {
|
||||
const users = db
|
||||
.prepare(
|
||||
`SELECT email, name, role, avatar_color FROM users
|
||||
ORDER BY CASE role WHEN 'admin' THEN 0 WHEN 'owner' THEN 1 ELSE 2 END, name`
|
||||
)
|
||||
.all();
|
||||
res.json({ users });
|
||||
});
|
||||
Reference in New Issue
Block a user