Files
assetsTracker/scripts/setup-appwrite.js
2026-03-08 08:34:55 +01:00

362 lines
12 KiB
JavaScript

import { Client, Databases, Teams, Users, ID, Permission, Role, Query } from 'node-appwrite';
import { readFileSync } from 'fs';
import { resolve, dirname } from 'path';
import { fileURLToPath } from 'url';
const __dirname = dirname(fileURLToPath(import.meta.url));
function loadEnv() {
const envPath = resolve(__dirname, '..', '.env');
const lines = readFileSync(envPath, 'utf-8').split('\n');
for (const line of lines) {
const trimmed = line.trim();
if (!trimmed || trimmed.startsWith('#')) continue;
const eqIdx = trimmed.indexOf('=');
if (eqIdx === -1) continue;
const key = trimmed.slice(0, eqIdx).trim();
const value = trimmed.slice(eqIdx + 1).trim();
process.env[key] = value;
}
}
loadEnv();
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';
if (!ENDPOINT || !PROJECT_ID || !API_KEY || API_KEY === 'YOUR_API_KEY_HERE') {
console.error('Bitte APPWRITE_ENDPOINT, VITE_APPWRITE_PROJECT_ID und APPWRITE_API_KEY in .env setzen.');
process.exit(1);
}
const client = new Client()
.setEndpoint(ENDPOINT)
.setProject(PROJECT_ID)
.setKey(API_KEY);
const databases = new Databases(client);
const teamsService = new Teams(client);
const users = new Users(client);
const TEAM_ROLES = ['admin', 'firmenleiter', 'filialleiter', 'service', 'lager'];
async function createDatabase() {
try {
const db = await databases.create(DATABASE_ID, 'DefektTrack DB');
console.log(`Datenbank erstellt: ${db.$id}`);
} catch (err) {
if (err.code === 409) {
console.log(`Datenbank existiert bereits: ${DATABASE_ID}`);
} else {
throw err;
}
}
}
async function createLocationsCollection() {
const COLLECTION_ID = 'locations';
try {
await databases.createCollection(
DATABASE_ID,
COLLECTION_ID,
'Standorte',
[
Permission.read(Role.users()),
Permission.create(Role.team('admin')),
Permission.update(Role.team('admin')),
Permission.delete(Role.team('admin')),
]
);
console.log('Collection erstellt: locations');
} catch (err) {
if (err.code === 409) {
console.log('Collection existiert bereits: locations');
return;
}
throw err;
}
await databases.createStringAttribute(DATABASE_ID, COLLECTION_ID, 'name', 128, true);
await databases.createStringAttribute(DATABASE_ID, COLLECTION_ID, 'address', 256, false, '');
await databases.createBooleanAttribute(DATABASE_ID, COLLECTION_ID, 'isActive', false, true);
console.log(' Attribute fuer locations erstellt (name, address, isActive)');
}
async function createUsersMetaCollection() {
const COLLECTION_ID = 'users_meta';
try {
await databases.createCollection(
DATABASE_ID,
COLLECTION_ID,
'Benutzer-Metadaten',
[
Permission.read(Role.users()),
Permission.create(Role.team('admin')),
Permission.update(Role.users()),
Permission.delete(Role.team('admin')),
]
);
console.log('Collection erstellt: users_meta');
} catch (err) {
if (err.code === 409) {
console.log('Collection existiert bereits: users_meta');
return;
}
throw err;
}
await databases.createStringAttribute(DATABASE_ID, COLLECTION_ID, 'userId', 64, true);
await databases.createStringAttribute(DATABASE_ID, COLLECTION_ID, 'locationId', 64, false, '');
await databases.createStringAttribute(DATABASE_ID, COLLECTION_ID, 'userName', 128, false, '');
await databases.createStringAttribute(DATABASE_ID, COLLECTION_ID, 'role', 32, true);
await databases.createBooleanAttribute(DATABASE_ID, COLLECTION_ID, 'mustChangePassword', false, true);
console.log(' Attribute fuer users_meta erstellt (userId, locationId, userName, role, mustChangePassword)');
}
async function createLagerstandorteCollection() {
const COLLECTION_ID = 'lagerstandorte';
try {
await databases.createCollection(
DATABASE_ID,
COLLECTION_ID,
'Lagerstandorte',
[
Permission.read(Role.users()),
Permission.create(Role.team('admin')),
Permission.update(Role.team('admin')),
Permission.delete(Role.team('admin')),
Permission.create(Role.team('filialleiter')),
Permission.update(Role.team('filialleiter')),
Permission.delete(Role.team('filialleiter')),
]
);
console.log('Collection erstellt: lagerstandorte');
} catch (err) {
if (err.code === 409) {
console.log('Collection existiert bereits: lagerstandorte');
return;
}
throw err;
}
await databases.createStringAttribute(DATABASE_ID, COLLECTION_ID, 'name', 128, true);
await databases.createStringAttribute(DATABASE_ID, COLLECTION_ID, 'locationId', 64, true);
await databases.createBooleanAttribute(DATABASE_ID, COLLECTION_ID, 'isActive', false, true);
console.log(' Attribute fuer lagerstandorte erstellt (name, locationId, isActive)');
}
async function createAssetsCollection() {
const COLLECTION_ID = 'assets';
try {
await databases.createCollection(
DATABASE_ID,
COLLECTION_ID,
'Assets',
[
Permission.read(Role.users()),
Permission.create(Role.users()),
Permission.update(Role.users()),
Permission.delete(Role.team('admin')),
Permission.delete(Role.team('filialleiter')),
]
);
console.log('Collection erstellt: assets');
} catch (err) {
if (err.code === 409) {
console.log('Collection existiert bereits: assets');
return;
}
throw err;
}
await databases.createStringAttribute(DATABASE_ID, COLLECTION_ID, 'erlNummer', 64, true);
await databases.createStringAttribute(DATABASE_ID, COLLECTION_ID, 'seriennummer', 128, true);
await databases.createStringAttribute(DATABASE_ID, COLLECTION_ID, 'artikelNr', 64, false, '');
await databases.createStringAttribute(DATABASE_ID, COLLECTION_ID, 'bezeichnung', 256, false, '');
await databases.createStringAttribute(DATABASE_ID, COLLECTION_ID, 'defekt', 1024, false, '');
await databases.createStringAttribute(DATABASE_ID, COLLECTION_ID, 'lagerstandortId', 64, false, '');
await databases.createStringAttribute(DATABASE_ID, COLLECTION_ID, 'zustaendig', 128, true);
await databases.createStringAttribute(DATABASE_ID, COLLECTION_ID, 'status', 32, true);
await databases.createStringAttribute(DATABASE_ID, COLLECTION_ID, 'prio', 16, true);
await databases.createStringAttribute(DATABASE_ID, COLLECTION_ID, 'kommentar', 2048, false, '');
await databases.createStringAttribute(DATABASE_ID, COLLECTION_ID, 'createdBy', 128, false, '');
await databases.createStringAttribute(DATABASE_ID, COLLECTION_ID, 'lastEditedBy', 128, false, '');
console.log(' Attribute fuer assets erstellt (erlNummer, seriennummer, artikelNr, bezeichnung, defekt, lagerstandortId, zustaendig, status, prio, kommentar, createdBy, lastEditedBy)');
}
async function createAuditLogsCollection() {
const COLLECTION_ID = 'audit_logs';
try {
await databases.createCollection(
DATABASE_ID,
COLLECTION_ID,
'Audit Logs',
[
Permission.read(Role.users()),
Permission.create(Role.users()),
]
);
console.log('Collection erstellt: audit_logs');
} catch (err) {
if (err.code === 409) {
console.log('Collection existiert bereits: audit_logs');
return;
}
throw err;
}
await databases.createStringAttribute(DATABASE_ID, COLLECTION_ID, 'assetId', 64, true);
await databases.createStringAttribute(DATABASE_ID, COLLECTION_ID, 'action', 64, true);
await databases.createStringAttribute(DATABASE_ID, COLLECTION_ID, 'details', 2048, false, '');
await databases.createStringAttribute(DATABASE_ID, COLLECTION_ID, 'userId', 64, true);
await databases.createStringAttribute(DATABASE_ID, COLLECTION_ID, 'userName', 128, true);
await new Promise((r) => setTimeout(r, 2000));
try {
await databases.createIndex(DATABASE_ID, COLLECTION_ID, 'idx_assetId', 'key', ['assetId'], ['ASC']);
console.log(' Index erstellt: idx_assetId');
} catch (err) {
if (err.code === 409) console.log(' Index existiert bereits: idx_assetId');
else throw err;
}
console.log(' Attribute fuer audit_logs erstellt (assetId, action, details, userId, userName)');
}
async function createTeams() {
for (const role of TEAM_ROLES) {
try {
await teamsService.create(role, role.charAt(0).toUpperCase() + role.slice(1));
console.log(`Team erstellt: ${role}`);
} catch (err) {
if (err.code === 409) {
console.log(`Team existiert bereits: ${role}`);
} else {
throw err;
}
}
}
}
async function createDefaultLocation() {
const existing = await databases.listDocuments(DATABASE_ID, 'locations', [Query.limit(1)]);
if (existing.documents.length > 0) {
console.log(`Filiale existiert bereits: "${existing.documents[0].name}"`);
return existing.documents[0].$id;
}
await new Promise((r) => setTimeout(r, 2000));
const loc = await databases.createDocument(DATABASE_ID, 'locations', ID.unique(), {
name: 'Hauptfiliale',
address: '',
isActive: true,
});
console.log(`Filiale erstellt: "Hauptfiliale" (${loc.$id})`);
return loc.$id;
}
async function createAdminUser(defaultLocationId) {
const ADMIN_EMAIL = 'admin@defekttrack.local';
const ADMIN_PASSWORD = 'Admin1234!';
const ADMIN_NAME = 'Administrator';
let userId;
try {
const user = await users.create(ID.unique(), ADMIN_EMAIL, undefined, ADMIN_PASSWORD, ADMIN_NAME);
userId = user.$id;
console.log(`Admin-User erstellt: ${ADMIN_EMAIL} (ID: ${userId})`);
} catch (err) {
if (err.code === 409) {
console.log(`Admin-User existiert bereits: ${ADMIN_EMAIL}`);
const userList = await users.list([Query.equal('email', [ADMIN_EMAIL])]);
if (userList.users.length > 0) {
userId = userList.users[0].$id;
} else {
console.log(' Konnte bestehenden Admin nicht finden, ueberspringe Team-Zuordnung.');
return;
}
} else {
throw err;
}
}
try {
await teamsService.createMembership('admin', [], ADMIN_EMAIL, userId, undefined, `${ENDPOINT}/auth/confirm`);
console.log(' Admin dem Team "admin" hinzugefuegt');
} catch (err) {
if (err.code === 409) {
console.log(' Admin ist bereits im Team "admin"');
} else {
console.warn(' Team-Membership Warnung:', err.message);
}
}
try {
await databases.createDocument(DATABASE_ID, 'users_meta', ID.unique(), {
userId,
locationId: defaultLocationId || '',
userName: ADMIN_NAME,
role: 'admin',
mustChangePassword: false,
});
console.log(' users_meta Dokument fuer Admin erstellt');
} catch (err) {
if (err.code === 409) {
console.log(' users_meta Dokument existiert bereits');
} else {
console.warn(' users_meta Warnung:', err.message);
}
}
}
async function main() {
console.log('=== DefektTrack Appwrite Setup ===');
console.log(`Endpoint: ${ENDPOINT}`);
console.log(`Projekt: ${PROJECT_ID}`);
console.log('');
await createDatabase();
console.log('');
await createLocationsCollection();
console.log('');
await createUsersMetaCollection();
console.log('');
await createLagerstandorteCollection();
console.log('');
await createAssetsCollection();
console.log('');
await createAuditLogsCollection();
console.log('');
await createTeams();
console.log('');
const defaultLocationId = await createDefaultLocation();
console.log('');
await createAdminUser(defaultLocationId);
console.log('');
console.log('=== Setup abgeschlossen ===');
console.log('');
console.log('Admin-Login:');
console.log(' E-Mail: admin@defekttrack.local');
console.log(' Passwort: Admin1234!');
console.log('');
console.log('Vergiss nicht, den API-Key aus .env zu entfernen oder sicher aufzubewahren.');
}
main().catch((err) => {
console.error('Setup fehlgeschlagen:', err);
process.exit(1);
});