Files
assetsTracker/server/index.js
2026-03-15 21:19:49 +01:00

132 lines
5.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import dotenv from 'dotenv';
import { fileURLToPath } from 'url';
import { dirname, resolve } from 'path';
const __dirname = dirname(fileURLToPath(import.meta.url));
dotenv.config({ path: resolve(__dirname, '..', '.env') });
import express from 'express';
import cors from 'cors';
import { Client, Users, Teams, Databases, ID, Query } from 'node-appwrite';
const ENDPOINT = process.env.APPWRITE_ENDPOINT;
const PROJECT_ID = process.env.VITE_APPWRITE_PROJECT_ID;
const API_KEY = process.env.APPWRITE_API_KEY;
const DATABASE_ID = process.env.VITE_APPWRITE_DATABASE_ID || 'defekttrack_db';
const ADMIN_SECRET = process.env.ADMIN_SECRET;
const TEAM_ROLES = ['admin', 'firmenleiter', 'filialleiter', 'service', 'lager'];
// #region agent log
function debugLog(location, message, data, hypothesisId) {
const payload = { sessionId: '405dbc', location, message, data: data || {}, timestamp: Date.now(), hypothesisId };
fetch('http://127.0.0.1:7886/ingest/990166f5-529c-4789-bcc2-9ebbe976f059', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Debug-Session-Id': '405dbc' }, body: JSON.stringify(payload) }).catch(() => {});
}
// #endregion
const app = express();
app.use(cors({ origin: true, credentials: true }));
app.use(express.json());
function requireAdminSecret(req, res, next) {
const secret = req.headers['x-admin-secret'];
if (!ADMIN_SECRET || secret !== ADMIN_SECRET) {
// #region agent log
debugLog('server/index.js:middleware', '403 admin secret mismatch', { hasServerSecret: !!ADMIN_SECRET, hasHeader: !!secret, headerLength: typeof secret === 'string' ? secret.length : 0 }, 'C');
// #endregion
return res.status(403).json({ error: 'Forbidden ADMIN_SECRET und VITE_ADMIN_SECRET in .env müssen identisch sein. Beide Dev-Server (Vite + npm run dev:api) nach .env-Änderung neu starten.' });
}
next();
}
app.post('/api/admin/create-user', requireAdminSecret, async (req, res) => {
// #region agent log
debugLog('server/index.js:route', 'create-user route hit', { bodyKeys: Object.keys(req.body || {}) }, 'A');
// #endregion
try {
const { email, password, name, locationId, role, mustChangePassword } = req.body || {};
if (!email || !password || !name || !locationId || !role) {
return res.status(400).json({
error: 'Fehlende Felder',
required: ['email', 'password', 'name', 'locationId', 'role'],
});
}
if (!TEAM_ROLES.includes(role)) {
return res.status(400).json({
error: 'Ungültige Rolle',
allowed: TEAM_ROLES,
});
}
if (!ENDPOINT || !PROJECT_ID || !API_KEY) {
// #region agent log
debugLog('server/index.js:env', 'env missing', { hasEndpoint: !!ENDPOINT, hasProjectId: !!PROJECT_ID, hasApiKey: !!API_KEY }, 'B');
// #endregion
return res.status(500).json({ error: 'Server-Konfiguration unvollständig (APPWRITE_ENDPOINT, VITE_APPWRITE_PROJECT_ID, APPWRITE_API_KEY in .env prüfen)' });
}
// #region agent log
debugLog('server/index.js:env', 'env check passed', { hasEndpoint: true, hasProjectId: true, hasApiKey: true }, 'B');
// #endregion
const client = new Client().setEndpoint(ENDPOINT).setProject(PROJECT_ID).setKey(API_KEY);
const users = new Users(client);
const teams = new Teams(client);
const databases = new Databases(client);
let userId;
// #region agent log
debugLog('server/index.js:users', 'before users.create', { email: !!email, role }, 'D');
// #endregion
try {
const user = await users.create(ID.unique(), email, undefined, password, name);
userId = user.$id;
} catch (err) {
// #region agent log
debugLog('server/index.js:users', 'users.create failed', { code: err.code, message: err.message }, 'D');
// #endregion
if (err.code === 409) {
const list = await users.list([Query.equal('email', [email])]);
if (list.users.length > 0) userId = list.users[0].$id;
}
if (!userId) {
return res.status(400).json({ error: err.message || 'User anlegen fehlgeschlagen' });
}
}
try {
await teams.createMembership(role, [], email, userId, undefined, `${ENDPOINT}/auth/confirm`);
} catch (err) {
if (err.code !== 409) {
console.warn('Team-Membership:', err.message);
}
}
try {
await databases.createDocument(DATABASE_ID, 'users_meta', ID.unique(), {
userId,
locationId: locationId || '',
userName: name,
role,
mustChangePassword: mustChangePassword !== false,
});
} catch (err) {
if (err.code !== 409) {
console.warn('users_meta:', err.message);
}
}
return res.status(201).json({ userId, email, name, role, locationId });
} catch (err) {
// #region agent log
debugLog('server/index.js:outer', 'outer catch 500', { message: err.message, code: err?.code, name: err?.name }, 'E');
// #endregion
console.error('create-user error:', err);
const message = err.message || err.toString?.() || 'Interner Serverfehler';
return res.status(500).json({ error: message });
}
});
const PORT = process.env.API_PORT || 3001;
app.listen(PORT, () => {
console.log(`API server http://localhost:${PORT}`);
});