feat: initial commit
This commit is contained in:
361
scripts/setup-appwrite.js
Normal file
361
scripts/setup-appwrite.js
Normal file
@@ -0,0 +1,361 @@
|
||||
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);
|
||||
});
|
||||
Reference in New Issue
Block a user