#!/usr/bin/env node /** * Legt die Collection portalMessages (Kunde-Admin-Chat) in woms-database an. * Idempotent: existierende Collection/Attribute/Indexe werden uebersprungen. * Usage: APPWRITE_API_KEY=... node scripts/setup-chat-collection.mjs */ const endpoint = (process.env.APPWRITE_ENDPOINT || 'https://ticket.webklar.com/v1').replace(/\/$/, '') const projectId = process.env.APPWRITE_PROJECT_ID || '6a1058610003c5a13a05' const apiKey = process.env.APPWRITE_API_KEY const databaseId = process.env.APPWRITE_DATABASE_ID || 'woms-database' const COLLECTION_ID = 'portalMessages' if (!apiKey) { console.error('APPWRITE_API_KEY erforderlich') process.exit(1) } async function aw(path, { method = 'GET', body } = {}) { const response = await fetch(`${endpoint}${path}`, { method, headers: { 'Content-Type': 'application/json', 'X-Appwrite-Project': projectId, 'X-Appwrite-Key': apiKey, }, body: body ? JSON.stringify(body) : undefined, }) const data = await response.json().catch(() => ({})) if (!response.ok) { const err = new Error(data.message || `Appwrite ${response.status}`) err.status = response.status err.type = data.type throw err } return data } async function ensure(label, fn) { try { await fn() console.log(`+ ${label}`) } catch (e) { if (e.status === 409 || /already exists/i.test(e.message)) { console.log(`= ${label} (existiert)`) } else { throw new Error(`${label}: ${e.message}`) } } } async function waitForAttribute(key, maxSec = 30) { for (let i = 0; i < maxSec; i += 1) { const attr = await aw( `/databases/${databaseId}/collections/${COLLECTION_ID}/attributes/${key}` ).catch(() => null) if (attr?.status === 'available') return await new Promise((r) => setTimeout(r, 1000)) } throw new Error(`Attribut ${key} wurde nicht verfuegbar`) } const base = `/databases/${databaseId}/collections` await ensure(`Collection ${COLLECTION_ID}`, () => aw(base, { method: 'POST', body: { collectionId: COLLECTION_ID, name: 'Portal Messages (Kunde-Admin-Chat)', documentSecurity: false, permissions: [], }, }) ) const attributes = [ { kind: 'string', key: 'customerId', size: 64, required: true }, { kind: 'string', key: 'sender', size: 16, required: true }, { kind: 'string', key: 'senderName', size: 128, required: false }, { kind: 'string', key: 'text', size: 4000, required: true }, { kind: 'boolean', key: 'readByAdmin', required: false }, { kind: 'boolean', key: 'readByCustomer', required: false }, { kind: 'datetime', key: 'createdAt', required: true }, ] for (const attr of attributes) { const { kind, ...body } = attr await ensure(`Attribut ${attr.key}`, () => aw(`${base}/${COLLECTION_ID}/attributes/${kind}`, { method: 'POST', body }) ) } for (const attr of attributes) { await waitForAttribute(attr.key) } console.log('Alle Attribute verfuegbar.') const indexes = [ { key: 'idx_customer_created', type: 'key', attributes: ['customerId', 'createdAt'], orders: ['ASC', 'DESC'] }, { key: 'idx_created', type: 'key', attributes: ['createdAt'], orders: ['DESC'] }, { key: 'idx_read_admin', type: 'key', attributes: ['readByAdmin', 'sender'], orders: ['ASC', 'ASC'] }, { key: 'idx_customer_read', type: 'key', attributes: ['customerId', 'readByCustomer'], orders: ['ASC', 'ASC'] }, ] for (const idx of indexes) { await ensure(`Index ${idx.key}`, () => aw(`${base}/${COLLECTION_ID}/indexes`, { method: 'POST', body: idx }) ) } console.log('Fertig.')