// Kunden-Konto: Profil, Abo, Instanzen (Liste), Profil-Update, Passwort ändern. import { Router } from "express"; import { one, query } from "../db.js"; import { requireAuth, hashPassword, verifyPassword } from "../auth.js"; import { publicPlans } from "../plans.js"; export const accountRouter = Router(); // Profil-Spalten, die der Kunde selbst bearbeiten darf (Whitelist). const PROFILE_FIELDS = ["company", "contact_name", "street", "zip", "city", "country", "phone"]; // ── Konto-Übersicht: Konto + Profil + aktuelles Abo + alle Instanzen ───────── accountRouter.get("/me", requireAuth, async (req, res) => { const account = await one( `select id, email, company, contact_name, street, zip, city, country, phone, is_admin, created_at from accounts where id = $1`, [req.account.id] ); if (!account) return res.status(404).json({ error: "Konto nicht gefunden." }); const subscription = await one( `select plan, status, current_period_end, stripe_subscription_id from subscriptions where account_id = $1 order by created_at desc limit 1`, [req.account.id] ); const { rows: instances } = await query( `select id, studio_slug, label, instance_url, status, created_at from instances where account_id = $1 order by created_at asc`, [req.account.id] ); res.json({ account, subscription: subscription || null, instances, // Rückwärtskompatibel: erste Instanz auch einzeln (altes Frontend). instance: instances[0] || null, plans: publicPlans(), }); }); // ── Profil aktualisieren ───────────────────────────────────────────────────── accountRouter.patch("/me", requireAuth, async (req, res) => { const updates = []; const values = []; for (const f of PROFILE_FIELDS) { if (req.body[f] !== undefined) { values.push(req.body[f] === "" ? null : req.body[f]); updates.push(`${f} = $${values.length}`); } } if (!updates.length) return res.status(400).json({ error: "Keine Felder zum Aktualisieren." }); values.push(req.account.id); const account = await one( `update accounts set ${updates.join(", ")}, updated_at = now() where id = $${values.length} returning id, email, company, contact_name, street, zip, city, country, phone`, values ); res.json({ account }); }); // ── Passwort ändern ────────────────────────────────────────────────────────── accountRouter.post("/password", requireAuth, async (req, res) => { const { currentPassword, newPassword } = req.body || {}; if (!newPassword || newPassword.length < 8) { return res.status(400).json({ error: "Neues Passwort min. 8 Zeichen." }); } const row = await one("select password_hash from accounts where id = $1", [req.account.id]); if (!row || !(await verifyPassword(currentPassword || "", row.password_hash))) { return res.status(403).json({ error: "Aktuelles Passwort falsch." }); } await query("update accounts set password_hash = $1, updated_at = now() where id = $2", [ await hashPassword(newPassword), req.account.id, ]); res.json({ ok: true }); });